├── .gitignore
├── .rubocop.yml
├── .travis.yml
├── CHANGELOG.md
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── Rakefile
├── aliyun-oss.gemspec
├── bin
├── console
└── setup
├── demo
├── .gitignore
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
│ ├── assets
│ │ ├── images
│ │ │ └── .keep
│ │ ├── javascripts
│ │ │ └── application.js
│ │ └── stylesheets
│ │ │ ├── application.scss
│ │ │ └── home.scss
│ ├── controllers
│ │ ├── application_controller.rb
│ │ ├── concerns
│ │ │ └── .keep
│ │ └── home_controller.rb
│ ├── helpers
│ │ └── application_helper.rb
│ ├── mailers
│ │ └── .keep
│ ├── models
│ │ ├── .keep
│ │ └── concerns
│ │ │ └── .keep
│ ├── services
│ │ └── aliyun_service.rb
│ └── views
│ │ ├── home
│ │ ├── index.html.erb
│ │ ├── new_post.html.erb
│ │ └── new_put.html.erb
│ │ └── layouts
│ │ └── application.html.erb
├── bin
│ ├── bundle
│ ├── rails
│ └── rake
├── config.ru
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── database.yml.example
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── backtrace_silencers.rb
│ │ ├── cookies_serializer.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── session_store.rb
│ │ └── wrap_parameters.rb
│ ├── locales
│ │ └── en.yml
│ ├── routes.rb
│ └── secrets.yml.example
├── db
│ └── seeds.rb
├── demo_development
├── lib
│ ├── assets
│ │ └── .keep
│ └── tasks
│ │ └── .keep
├── log
│ └── .keep
├── public
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ ├── favicon.ico
│ └── robots.txt
├── test
│ ├── controllers
│ │ └── .keep
│ ├── fixtures
│ │ └── .keep
│ ├── helpers
│ │ └── .keep
│ ├── integration
│ │ └── .keep
│ ├── mailers
│ │ └── .keep
│ ├── models
│ │ └── .keep
│ └── test_helper.rb
└── vendor
│ └── assets
│ ├── javascripts
│ └── .keep
│ └── stylesheets
│ └── .keep
├── lib
└── aliyun
│ ├── oss.rb
│ └── oss
│ ├── api
│ ├── bucket_multiparts.rb
│ ├── bucket_objects.rb
│ ├── bucket_property.rb
│ └── buckets.rb
│ ├── authorization.rb
│ ├── client.rb
│ ├── client
│ ├── bucket_multiparts.rb
│ ├── bucket_objects.rb
│ ├── buckets.rb
│ └── clients.rb
│ ├── error.rb
│ ├── http.rb
│ ├── struct.rb
│ ├── struct
│ ├── bucket.rb
│ ├── cors.rb
│ ├── directory.rb
│ ├── file.rb
│ ├── lifecycle.rb
│ ├── logging.rb
│ ├── multipart.rb
│ ├── object.rb
│ ├── part.rb
│ ├── referer.rb
│ └── website.rb
│ ├── utils.rb
│ ├── version.rb
│ └── xml_generator.rb
├── test
├── aliyun
│ ├── authorization_test.rb
│ ├── client
│ │ ├── bucket_multiparts_service_test.rb
│ │ ├── bucket_objects_service_test.rb
│ │ └── buckets_service_test.rb
│ ├── client_test.rb
│ ├── struct
│ │ ├── bucket_test.rb
│ │ ├── directory_test.rb
│ │ ├── file_test.rb
│ │ ├── multipart_test.rb
│ │ └── object_test.rb
│ └── utils_test.rb
├── fixtures
│ ├── bucket
│ │ ├── acl.xml
│ │ ├── cors.xml
│ │ ├── date_lifecycle.xml
│ │ ├── days_lifecycle.xml
│ │ ├── location.xml
│ │ ├── logging.xml
│ │ ├── no_lifecycle.xml
│ │ ├── no_logging.xml
│ │ ├── no_referer.xml
│ │ ├── referer.xml
│ │ └── website.xml
│ ├── bucket_multiparts
│ │ ├── init.xml
│ │ └── list.xml
│ ├── bucket_objects
│ │ ├── list.xml
│ │ └── list_dir.xml
│ ├── buckets
│ │ └── list.xml
│ ├── directory
│ │ └── list.xml
│ ├── error
│ │ ├── 400.xml
│ │ ├── 404.xml
│ │ └── 409.xml
│ ├── multipart
│ │ ├── complete.xml
│ │ └── list_parts.xml
│ ├── object
│ │ └── acl.xml
│ └── sample.txt
└── test_helper.rb
├── todo.md
└── wiki
├── bucket.md
├── cors.md
├── error.md
├── get_start.md
├── installation.md
├── lifecycle.md
├── multipart.md
├── object.md
└── object_based
├── bucket.md
├── cors.md
├── error.md
├── get_start.md
├── installation.md
├── lifecycle.md
├── multipart.md
└── object.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /.bundle/
2 | /.yardoc
3 | /Gemfile.lock
4 | /_yardoc/
5 | /coverage/
6 | /doc/
7 | /pkg/
8 | /spec/reports/
9 | /tmp/
10 | demo/config/secrets.yml
11 | demo/config/database.yml
12 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | # This is the configuration used to check the rubocop source code.
2 |
3 | AllCops:
4 | Exclude:
5 | - 'demo/**/*'
6 |
7 | Metrics/LineLength:
8 | Max: 100
9 | Enabled: false
10 |
11 | Style/Documentation:
12 | Enabled: false
13 |
14 | Style/DoubleNegation:
15 | Enabled: false
16 |
17 | Metrics/ClassLength:
18 | Enabled: false
19 |
20 | Style/AccessorMethodName:
21 | Enabled: false
22 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | rvm:
3 | - 2.0.0
4 | - 2.1.0
5 | - 2.2.0
6 | - 2.3.0
7 | before_install: gem install bundler
8 | script:
9 | - bundle exec rake test
10 | - bundle exec rubocop
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | 0.1.8
2 | -----
3 |
4 | - Escape special charaters in object name;
5 |
6 | 0.1.7
7 | -----
8 |
9 | - Remove special charaters in object name;
10 |
11 | 0.1.6
12 | -----
13 |
14 | - Fix private bucket `bucket_get_object_share_link` method sometime will got `SignatureDoesNotMatch` bug.
15 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # Specify your gem's dependencies in ruby-oss-sdk.gemspec
4 | gemspec
5 | gem 'coveralls', require: false
6 | gem 'simplecov', require: false
7 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | aliyun-oss-sdk (0.1.8)
5 | addressable
6 | gyoku
7 | httparty
8 |
9 | GEM
10 | remote: https://rubygems.org/
11 | specs:
12 | addressable (2.3.8)
13 | ast (2.1.0)
14 | astrolabe (1.3.1)
15 | parser (~> 2.2)
16 | builder (3.2.2)
17 | coveralls (0.8.3)
18 | json (~> 1.8)
19 | rest-client (>= 1.6.8, < 2)
20 | simplecov (~> 0.10.0)
21 | term-ansicolor (~> 1.3)
22 | thor (~> 0.19.1)
23 | crack (0.4.2)
24 | safe_yaml (~> 1.0.0)
25 | docile (1.1.5)
26 | domain_name (0.5.25)
27 | unf (>= 0.0.5, < 1.0.0)
28 | gyoku (1.3.1)
29 | builder (>= 2.1.2)
30 | hashdiff (0.2.2)
31 | http-cookie (1.0.2)
32 | domain_name (~> 0.5)
33 | httparty (0.13.7)
34 | json (~> 1.8)
35 | multi_xml (>= 0.5.2)
36 | json (1.8.3)
37 | metaclass (0.0.4)
38 | mime-types (2.6.2)
39 | minitest (5.8.1)
40 | mocha (1.1.0)
41 | metaclass (~> 0.0.1)
42 | multi_xml (0.5.5)
43 | netrc (0.10.3)
44 | parser (2.2.2.6)
45 | ast (>= 1.1, < 3.0)
46 | powerpack (0.1.1)
47 | rainbow (2.0.0)
48 | rake (10.4.2)
49 | rest-client (1.8.0)
50 | http-cookie (>= 1.0.2, < 2.0)
51 | mime-types (>= 1.16, < 3.0)
52 | netrc (~> 0.7)
53 | rubocop (0.34.2)
54 | astrolabe (~> 1.3)
55 | parser (>= 2.2.2.5, < 3.0)
56 | powerpack (~> 0.1)
57 | rainbow (>= 1.99.1, < 3.0)
58 | ruby-progressbar (~> 1.4)
59 | ruby-progressbar (1.7.5)
60 | safe_yaml (1.0.4)
61 | simplecov (0.10.0)
62 | docile (~> 1.1.0)
63 | json (~> 1.8)
64 | simplecov-html (~> 0.10.0)
65 | simplecov-html (0.10.0)
66 | term-ansicolor (1.3.2)
67 | tins (~> 1.0)
68 | thor (0.19.1)
69 | timecop (0.8.0)
70 | tins (1.6.0)
71 | unf (0.1.4)
72 | unf_ext
73 | unf_ext (0.0.7.1)
74 | webmock (1.22.1)
75 | addressable (>= 2.3.6)
76 | crack (>= 0.3.2)
77 | hashdiff
78 |
79 | PLATFORMS
80 | ruby
81 |
82 | DEPENDENCIES
83 | aliyun-oss-sdk!
84 | bundler
85 | coveralls
86 | minitest
87 | mocha
88 | rake
89 | rubocop
90 | simplecov
91 | timecop
92 | webmock
93 |
94 | BUNDLED WITH
95 | 1.11.2
96 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'bundler/gem_tasks'
2 | require 'rake/testtask'
3 | require 'rubocop/rake_task'
4 |
5 | Rake::TestTask.new(:test) do |t|
6 | t.libs << 'test'
7 | t.libs << 'lib'
8 | t.test_files = FileList['test/**/*_test.rb']
9 | end
10 |
11 | task default: :test
12 |
13 | task :test do
14 | Rake::Task['test'].invoke
15 | end
16 |
17 | RuboCop::RakeTask.new do |task|
18 | task.fail_on_error = false
19 | end
20 |
--------------------------------------------------------------------------------
/aliyun-oss.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require 'aliyun/oss/version'
5 |
6 | Gem::Specification.new do |spec|
7 | spec.name = 'aliyun-oss-sdk'
8 | spec.version = Aliyun::Oss::VERSION
9 | spec.authors = ['Newell Zhu']
10 | spec.email = ['zlx.star@gmail.com']
11 |
12 | spec.summary = 'Aliyun OSS Ruby SDK'
13 | spec.description = 'Aliyun OSS Ruby SDK'
14 | spec.homepage = 'https://github.com/zlx/aliyun-oss-sdk'
15 |
16 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|demo)/}) }
17 | spec.bindir = 'exe'
18 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19 | spec.require_paths = ['lib']
20 |
21 | spec.add_dependency 'httparty'
22 | spec.add_dependency 'addressable'
23 | spec.add_dependency 'gyoku'
24 |
25 | spec.add_development_dependency 'bundler'
26 | spec.add_development_dependency 'rake'
27 | spec.add_development_dependency 'minitest'
28 | spec.add_development_dependency 'mocha'
29 | spec.add_development_dependency 'webmock'
30 | spec.add_development_dependency 'timecop'
31 | spec.add_development_dependency 'rubocop'
32 | end
33 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'bundler/setup'
4 | require 'aliyun/oss'
5 |
6 | # You can add fixtures and/or initialization code here to make experimenting
7 | # with your gem easier. You can also use a different console, if you like.
8 |
9 | # (If you use this, don't forget to add pry to your Gemfile!)
10 | # require "pry"
11 | # Pry.start
12 |
13 | require 'irb'
14 | IRB.start
15 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -euo pipefail
3 | IFS=$'\n\t'
4 |
5 | bundle install
6 |
7 | # Do any other automated setup that you need to do here
8 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore the default SQLite database.
11 | /db/*.sqlite3
12 | /db/*.sqlite3-journal
13 |
14 | # Ignore all logfiles and tempfiles.
15 | /log/*.log
16 | /tmp
17 |
--------------------------------------------------------------------------------
/demo/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://ruby.taobao.org'
2 |
3 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
4 | gem 'rails', '4.1.0'
5 | # Use mysql as the database for Active Record
6 | gem 'sqlite3'
7 | # Use SCSS for stylesheets
8 | gem 'sass-rails', '~> 4.0.3'
9 | gem 'bootstrap-sass', '~> 3.3.5'
10 | # Use Uglifier as compressor for JavaScript assets
11 | gem 'uglifier', '>= 1.3.0'
12 | # Use CoffeeScript for .js.coffee assets and views
13 | gem 'coffee-rails', '~> 4.0.0'
14 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes
15 | # gem 'therubyracer', platforms: :ruby
16 |
17 | # Use jquery as the JavaScript library
18 | gem 'jquery-rails'
19 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
20 | gem 'turbolinks'
21 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
22 | gem 'jbuilder', '~> 2.0'
23 | # bundle exec rake doc:rails generates the API under doc/api.
24 | gem 'sdoc', '~> 0.4.0', group: :doc
25 |
26 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
27 | gem 'spring', group: :development
28 | gem 'aliyun-oss-sdk', path: '../', require: 'aliyun/oss'
29 | gem 'pry-byebug'
30 |
31 | # Use ActiveModel has_secure_password
32 | # gem 'bcrypt', '~> 3.1.7'
33 |
34 | # Use unicorn as the app server
35 | # gem 'unicorn'
36 |
37 | # Use Capistrano for deployment
38 | # gem 'capistrano-rails', group: :development
39 |
40 | # Use debugger
41 | # gem 'debugger', group: [:development, :test]
42 |
--------------------------------------------------------------------------------
/demo/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: ../
3 | specs:
4 | aliyun-oss-sdk (0.1.2)
5 | gyoku
6 | httparty
7 |
8 | GEM
9 | remote: https://ruby.taobao.org/
10 | specs:
11 | actionmailer (4.1.0)
12 | actionpack (= 4.1.0)
13 | actionview (= 4.1.0)
14 | mail (~> 2.5.4)
15 | actionpack (4.1.0)
16 | actionview (= 4.1.0)
17 | activesupport (= 4.1.0)
18 | rack (~> 1.5.2)
19 | rack-test (~> 0.6.2)
20 | actionview (4.1.0)
21 | activesupport (= 4.1.0)
22 | builder (~> 3.1)
23 | erubis (~> 2.7.0)
24 | activemodel (4.1.0)
25 | activesupport (= 4.1.0)
26 | builder (~> 3.1)
27 | activerecord (4.1.0)
28 | activemodel (= 4.1.0)
29 | activesupport (= 4.1.0)
30 | arel (~> 5.0.0)
31 | activesupport (4.1.0)
32 | i18n (~> 0.6, >= 0.6.9)
33 | json (~> 1.7, >= 1.7.7)
34 | minitest (~> 5.1)
35 | thread_safe (~> 0.1)
36 | tzinfo (~> 1.1)
37 | arel (5.0.1.20140414130214)
38 | autoprefixer-rails (6.0.3)
39 | execjs
40 | json
41 | bootstrap-sass (3.3.5)
42 | autoprefixer-rails (>= 5.0.0.1)
43 | sass (>= 3.2.19)
44 | builder (3.2.2)
45 | byebug (5.0.0)
46 | columnize (= 0.9.0)
47 | coderay (1.1.0)
48 | coffee-rails (4.0.1)
49 | coffee-script (>= 2.2.0)
50 | railties (>= 4.0.0, < 5.0)
51 | coffee-script (2.4.1)
52 | coffee-script-source
53 | execjs
54 | coffee-script-source (1.9.1.1)
55 | columnize (0.9.0)
56 | erubis (2.7.0)
57 | execjs (2.6.0)
58 | gyoku (1.3.1)
59 | builder (>= 2.1.2)
60 | hike (1.2.3)
61 | httparty (0.13.7)
62 | json (~> 1.8)
63 | multi_xml (>= 0.5.2)
64 | i18n (0.7.0)
65 | jbuilder (2.3.2)
66 | activesupport (>= 3.0.0, < 5)
67 | multi_json (~> 1.2)
68 | jquery-rails (3.1.4)
69 | railties (>= 3.0, < 5.0)
70 | thor (>= 0.14, < 2.0)
71 | json (1.8.3)
72 | mail (2.5.4)
73 | mime-types (~> 1.16)
74 | treetop (~> 1.4.8)
75 | method_source (0.8.2)
76 | mime-types (1.25.1)
77 | minitest (5.8.2)
78 | multi_json (1.11.2)
79 | multi_xml (0.5.5)
80 | polyglot (0.3.5)
81 | pry (0.10.3)
82 | coderay (~> 1.1.0)
83 | method_source (~> 0.8.1)
84 | slop (~> 3.4)
85 | pry-byebug (3.2.0)
86 | byebug (~> 5.0)
87 | pry (~> 0.10)
88 | rack (1.5.5)
89 | rack-test (0.6.3)
90 | rack (>= 1.0)
91 | rails (4.1.0)
92 | actionmailer (= 4.1.0)
93 | actionpack (= 4.1.0)
94 | actionview (= 4.1.0)
95 | activemodel (= 4.1.0)
96 | activerecord (= 4.1.0)
97 | activesupport (= 4.1.0)
98 | bundler (>= 1.3.0, < 2.0)
99 | railties (= 4.1.0)
100 | sprockets-rails (~> 2.0)
101 | railties (4.1.0)
102 | actionpack (= 4.1.0)
103 | activesupport (= 4.1.0)
104 | rake (>= 0.8.7)
105 | thor (>= 0.18.1, < 2.0)
106 | rake (10.4.2)
107 | rdoc (4.2.0)
108 | json (~> 1.4)
109 | sass (3.2.19)
110 | sass-rails (4.0.5)
111 | railties (>= 4.0.0, < 5.0)
112 | sass (~> 3.2.2)
113 | sprockets (~> 2.8, < 3.0)
114 | sprockets-rails (~> 2.0)
115 | sdoc (0.4.1)
116 | json (~> 1.7, >= 1.7.7)
117 | rdoc (~> 4.0)
118 | slop (3.6.0)
119 | spring (1.4.0)
120 | sprockets (2.12.4)
121 | hike (~> 1.2)
122 | multi_json (~> 1.0)
123 | rack (~> 1.0)
124 | tilt (~> 1.1, != 1.3.0)
125 | sprockets-rails (2.3.3)
126 | actionpack (>= 3.0)
127 | activesupport (>= 3.0)
128 | sprockets (>= 2.8, < 4.0)
129 | sqlite3 (1.3.11)
130 | thor (0.19.1)
131 | thread_safe (0.3.5)
132 | tilt (1.4.1)
133 | treetop (1.4.15)
134 | polyglot
135 | polyglot (>= 0.3.1)
136 | turbolinks (2.2.2)
137 | coffee-rails
138 | tzinfo (1.2.2)
139 | thread_safe (~> 0.1)
140 | uglifier (2.7.2)
141 | execjs (>= 0.3.0)
142 | json (>= 1.8.0)
143 |
144 | PLATFORMS
145 | ruby
146 |
147 | DEPENDENCIES
148 | aliyun-oss-sdk!
149 | bootstrap-sass (~> 3.3.5)
150 | coffee-rails (~> 4.0.0)
151 | jbuilder (~> 2.0)
152 | jquery-rails
153 | pry-byebug
154 | rails (= 4.1.0)
155 | sass-rails (~> 4.0.3)
156 | sdoc (~> 0.4.0)
157 | spring
158 | sqlite3
159 | turbolinks
160 | uglifier (>= 1.3.0)
161 |
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | ## USAGE
2 |
3 | ```
4 | cp config/secrets.yml{.example,}
5 | cp config/database.yml{.example,}
6 | bundle install
7 | bin/rails s
8 | ```
9 |
--------------------------------------------------------------------------------
/demo/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require File.expand_path('../config/application', __FILE__)
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/demo/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/app/assets/images/.keep
--------------------------------------------------------------------------------
/demo/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file.
9 | //
10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require jquery
14 | //= require jquery_ujs
15 | //= require turbolinks
16 | //= require bootstrap
17 |
--------------------------------------------------------------------------------
/demo/app/assets/stylesheets/application.scss:
--------------------------------------------------------------------------------
1 | @import "bootstrap-sprockets";
2 | @import "bootstrap";
3 |
4 | @import "home";
5 |
--------------------------------------------------------------------------------
/demo/app/assets/stylesheets/home.scss:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 70px;
3 | }
4 |
--------------------------------------------------------------------------------
/demo/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | # Prevent CSRF attacks by raising an exception.
3 | # For APIs, you may want to use :null_session instead.
4 | protect_from_forgery with: :exception
5 | end
6 |
--------------------------------------------------------------------------------
/demo/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/demo/app/controllers/home_controller.rb:
--------------------------------------------------------------------------------
1 | class HomeController < ApplicationController
2 | def index
3 | service = AliyunService.new
4 | @name = service.current_bucket.name
5 | @location = service.current_bucket.location!
6 | @objects = service.bucket_objects.list.select(&:file?)
7 | end
8 |
9 | def download
10 | service = AliyunService.new
11 | buffer = service.bucket_objects.get(params[:key])
12 | send_data buffer, filename: params[:key]
13 | end
14 |
15 | def new_put
16 | end
17 |
18 | def create_put
19 | service = AliyunService.new
20 | if params[:name].blank? || params[:file].blank?
21 | return render action: :new_put
22 | end
23 |
24 | service.bucket_objects.create(params[:name], params[:file].read)
25 | redirect_to root_path, notice: 'Upload Success'
26 | rescue Aliyun::Oss::RequestError => e
27 | Rails.logger.error(e.inspect)
28 | redirect_to root_path, alert: e.message
29 | end
30 |
31 | def new_post
32 | @access_key = Rails.application.secrets.aliyun_oss['access_key']
33 | secret_key = Rails.application.secrets.aliyun_oss['secret_key']
34 | bucket = Rails.application.secrets.aliyun_oss['bucket']
35 | host = Rails.application.secrets.aliyun_oss['host']
36 | @key = '${filename}'
37 | @acl = 'private'
38 | @return_url = 'http://localhost:3001/post_return'
39 | @username = 'newuser'
40 | policy_hash = {
41 | expiration: 15.minutes.since.strftime('%Y-%m-%dT%H:%M:%S.000Z'),
42 | conditions: [
43 | { bucket: bucket }
44 | ]
45 | }
46 |
47 | @policy = Aliyun::Oss::Authorization.get_base64_policy(policy_hash)
48 | @signature = Aliyun::Oss::Authorization.get_policy_signature(secret_key, policy_hash)
49 | @bucket_endpoint = Aliyun::Oss::Utils.get_endpoint(bucket, host)
50 | end
51 |
52 | def post_return
53 | redirect_to root_path, notice: 'Post Success'
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/demo/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/demo/app/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/app/mailers/.keep
--------------------------------------------------------------------------------
/demo/app/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/app/models/.keep
--------------------------------------------------------------------------------
/demo/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/app/models/concerns/.keep
--------------------------------------------------------------------------------
/demo/app/services/aliyun_service.rb:
--------------------------------------------------------------------------------
1 | class AliyunService < SimpleDelegator
2 | def initialize
3 | aliyun_oss = Rails.application.secrets.aliyun_oss
4 | @client = Aliyun::Oss::Client.new(
5 | aliyun_oss['access_key'],
6 | aliyun_oss['secret_key'],
7 | host: aliyun_oss['host'],
8 | bucket: aliyun_oss['bucket']
9 | )
10 | super(@client)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/demo/app/views/home/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 | Name
3 | <%= @name %>
4 | Location
5 | <%= @location %>
6 |
7 |
8 |
9 | <%= link_to 'Put Object', new_put_path, class: 'btn btn-primary' %>
10 | <%= link_to 'Post Object', new_post_path, class: 'btn btn-primary' %>
11 |
12 |
13 |
14 |
15 |
16 | Key
17 | etag
18 | type
19 | size
20 | last_modified
21 |
22 |
23 |
24 |
25 | <% @objects.each do |object| %>
26 |
27 | <%= object.key %>
28 | <%= object.etag %>
29 | <%= object.type %>
30 | <%= object.size %>
31 | <%= object.last_modified %>
32 |
33 | <%= link_to 'Download', download_path(key: object.key), method: :put %>
34 | <%= link_to 'Share Link', object.share_link(1.hour), target: '_blank' %>
35 |
36 |
37 | <% end %>
38 |
39 |
40 |
--------------------------------------------------------------------------------
/demo/app/views/home/new_post.html.erb:
--------------------------------------------------------------------------------
1 | POST Object
2 |
3 |
4 |
5 | <%= form_tag @bucket_endpoint, method: :post, multipart: true, class: 'form-horizontal' do -%>
6 | <%= hidden_field_tag 'OSSAccessKeyId', @access_key %>
7 | <%= hidden_field_tag 'policy', @policy %>
8 | <%= hidden_field_tag 'Signature', @signature %>
9 | <%= hidden_field_tag 'key', @key %>
10 | <%= hidden_field_tag 'success_action_redirect', @return_url %>
11 | <%= hidden_field_tag 'x-oss-meta-user', @username %>
12 | <%= hidden_field_tag 'x-oss-object-acl', @acl %>
13 |
14 | File
15 | <%= file_field_tag 'file' %>
16 |
17 |
22 | <% end -%>
23 |
--------------------------------------------------------------------------------
/demo/app/views/home/new_put.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= form_tag '/new_put', method: :post, multipart: true, class: 'form-horizontal' do -%>
6 |
12 |
13 | File
14 | <%= file_field_tag 'file' %>
15 |
16 |
21 | <% end -%>
22 |
--------------------------------------------------------------------------------
/demo/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Demo
5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7 | <%= csrf_meta_tags %>
8 |
9 |
10 |
11 |
12 |
13 |
22 |
23 |
24 |
25 |
26 |
27 | <% if flash[:notice] -%>
28 |
<%= flash[:notice] %>
29 | <% elsif flash[:alert] %>
30 |
<%= flash[:alert] %>
31 | <% end -%>
32 |
33 |
34 | <%= yield %>
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/demo/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/demo/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../../config/application', __FILE__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/demo/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/demo/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run Rails.application
5 |
--------------------------------------------------------------------------------
/demo/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | module Demo
10 | class Application < Rails::Application
11 | # Settings in config/environments/* take precedence over those specified here.
12 | # Application configuration should go into files in config/initializers
13 | # -- all .rb files in that directory are automatically loaded.
14 |
15 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
16 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
17 | # config.time_zone = 'Central Time (US & Canada)'
18 |
19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
21 | # config.i18n.default_locale = :de
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/demo/config/boot.rb:
--------------------------------------------------------------------------------
1 | # Set up gems listed in the Gemfile.
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 |
4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5 |
--------------------------------------------------------------------------------
/demo/config/database.yml.example:
--------------------------------------------------------------------------------
1 | # MySQL. Versions 5.0+ are recommended.
2 | #
3 | # Install the MYSQL driver
4 | # gem install mysql2
5 | #
6 | # Ensure the MySQL gem is defined in your Gemfile
7 | # gem 'mysql2'
8 | #
9 | # And be sure to use new-style password hashing:
10 | # http://dev.mysql.com/doc/refman/5.0/en/old-client.html
11 | #
12 | default: &default
13 | adapter: sqlite3
14 | encoding: utf8
15 | pool: 5
16 |
17 | development:
18 | <<: *default
19 | database: demo_development
20 |
21 | # Warning: The database defined as "test" will be erased and
22 | # re-generated from your development database when you run "rake".
23 | # Do not set this db to the same as development or production.
24 | test:
25 | <<: *default
26 | database: demo_test
27 |
28 | # As with config/secrets.yml, you never want to store sensitive information,
29 | # like your database password, in your source code. If your source code is
30 | # ever seen by anyone, they now have access to your database.
31 | #
32 | # Instead, provide the password as a unix environment variable when you boot
33 | # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
34 | # for a full rundown on how to provide these environment variables in a
35 | # production deployment.
36 | #
37 | # On Heroku and other platform providers, you may have a full connection URL
38 | # available as an environment variable. For example:
39 | #
40 | # DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
41 | #
42 | # You can use this database configuration with:
43 | #
44 | # production:
45 | # url: <%= ENV['DATABASE_URL'] %>
46 | #
47 | production:
48 | <<: *default
49 | database: demo_production
50 |
--------------------------------------------------------------------------------
/demo/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/demo/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports and disable caching.
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send.
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger.
20 | config.active_support.deprecation = :log
21 |
22 | # Raise an error on page load if there are pending migrations.
23 | config.active_record.migration_error = :page_load
24 |
25 | # Debug mode disables concatenation and preprocessing of assets.
26 | # This option may cause significant delays in view rendering with a large
27 | # number of complex assets.
28 | config.assets.debug = true
29 |
30 | # Adds additional error checking when serving assets at runtime.
31 | # Checks for improperly declared sprockets dependencies.
32 | # Raises helpful error messages.
33 | config.assets.raise_runtime_errors = true
34 |
35 | # Raises error for missing translations
36 | # config.action_view.raise_on_missing_translations = true
37 | end
38 |
--------------------------------------------------------------------------------
/demo/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
18 | # Add `rack-cache` to your Gemfile before enabling this.
19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
20 | # config.action_dispatch.rack_cache = true
21 |
22 | # Disable Rails's static asset server (Apache or nginx will already do this).
23 | config.serve_static_assets = false
24 |
25 | # Compress JavaScripts and CSS.
26 | config.assets.js_compressor = :uglifier
27 | # config.assets.css_compressor = :sass
28 |
29 | # Do not fallback to assets pipeline if a precompiled asset is missed.
30 | config.assets.compile = false
31 |
32 | # Generate digests for assets URLs.
33 | config.assets.digest = true
34 |
35 | # Version of your assets, change this if you want to expire all your assets.
36 | config.assets.version = '1.0'
37 |
38 | # Specifies the header that your server uses for sending files.
39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
41 |
42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
43 | # config.force_ssl = true
44 |
45 | # Set to :debug to see everything in the log.
46 | config.log_level = :info
47 |
48 | # Prepend all log lines with the following tags.
49 | # config.log_tags = [ :subdomain, :uuid ]
50 |
51 | # Use a different logger for distributed setups.
52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
53 |
54 | # Use a different cache store in production.
55 | # config.cache_store = :mem_cache_store
56 |
57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
58 | # config.action_controller.asset_host = "http://assets.example.com"
59 |
60 | # Precompile additional assets.
61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
62 | # config.assets.precompile += %w( search.js )
63 |
64 | # Ignore bad email addresses and do not raise email delivery errors.
65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
66 | # config.action_mailer.raise_delivery_errors = false
67 |
68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
69 | # the I18n.default_locale when a translation cannot be found).
70 | config.i18n.fallbacks = true
71 |
72 | # Send deprecation notices to registered listeners.
73 | config.active_support.deprecation = :notify
74 |
75 | # Disable automatic flushing of the log to improve performance.
76 | # config.autoflush_log = false
77 |
78 | # Use default logging formatter so that PID and timestamp are not suppressed.
79 | config.log_formatter = ::Logger::Formatter.new
80 |
81 | # Do not dump schema after migrations.
82 | config.active_record.dump_schema_after_migration = false
83 | end
84 |
--------------------------------------------------------------------------------
/demo/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure static asset server for tests with Cache-Control for performance.
16 | config.serve_static_assets = true
17 | config.static_cache_control = 'public, max-age=3600'
18 |
19 | # Show full error reports and disable caching.
20 | config.consider_all_requests_local = true
21 | config.action_controller.perform_caching = false
22 |
23 | # Raise exceptions instead of rendering exception templates.
24 | config.action_dispatch.show_exceptions = false
25 |
26 | # Disable request forgery protection in test environment.
27 | config.action_controller.allow_forgery_protection = false
28 |
29 | # Tell Action Mailer not to deliver emails to the real world.
30 | # The :test delivery method accumulates sent emails in the
31 | # ActionMailer::Base.deliveries array.
32 | config.action_mailer.delivery_method = :test
33 |
34 | # Print deprecation notices to the stderr.
35 | config.active_support.deprecation = :stderr
36 |
37 | # Raises error for missing translations
38 | # config.action_view.raise_on_missing_translations = true
39 | end
40 |
--------------------------------------------------------------------------------
/demo/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/demo/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
4 |
--------------------------------------------------------------------------------
/demo/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/demo/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/demo/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/demo/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_demo_session'
4 |
--------------------------------------------------------------------------------
/demo/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/demo/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
--------------------------------------------------------------------------------
/demo/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | root 'home#index'
3 | put 'download', to: 'home#download'
4 |
5 | get 'new_put', to: 'home#new_put'
6 | post 'new_put', to: 'home#create_put'
7 |
8 | get 'new_post', to: 'home#new_post'
9 | get 'post_return', to: 'home#post_return'
10 | end
11 |
--------------------------------------------------------------------------------
/demo/config/secrets.yml.example:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | development:
14 | secret_key_base: 2570d74321e57c9d4e6fbb5700701d1ccd2f6a08b3f7c0ac8a5a6fb4c564a9037bfa9fc2d3323d8d85492bbe0db781520760dedf449a0c777b0d8e40b73ec613
15 | aliyun_oss:
16 | access_key: xxx
17 | secret_key: xxx
18 | host: xxx
19 | bucket: bucket
20 |
21 |
22 | test:
23 | secret_key_base: 63d01fb2dd39090d5fc72a8ad93c6191a228fbce8b8094ff543c1ef07ba490dc9d2c34e225edee34c40dc734d64ea4f60646331c1e2f3eab37a506fd915d12d8
24 | aliyun_oss:
25 | access_key: xxx
26 | secret_key: xxx
27 | host: xxx
28 | bucket: bucket
29 |
30 | # Do not keep production secrets in the repository,
31 | # instead read values from the environment.
32 | production:
33 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
34 | aliyun_oss:
35 | access_key: xxx
36 | secret_key: xxx
37 | host: xxx
38 | bucket: bucket
39 |
--------------------------------------------------------------------------------
/demo/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7 | # Mayor.create(name: 'Emanuel', city: cities.first)
8 |
--------------------------------------------------------------------------------
/demo/demo_development:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/demo_development
--------------------------------------------------------------------------------
/demo/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/lib/assets/.keep
--------------------------------------------------------------------------------
/demo/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/lib/tasks/.keep
--------------------------------------------------------------------------------
/demo/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/log/.keep
--------------------------------------------------------------------------------
/demo/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/demo/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/demo/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/demo/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/public/favicon.ico
--------------------------------------------------------------------------------
/demo/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/demo/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/test/controllers/.keep
--------------------------------------------------------------------------------
/demo/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/test/fixtures/.keep
--------------------------------------------------------------------------------
/demo/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/test/helpers/.keep
--------------------------------------------------------------------------------
/demo/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/test/integration/.keep
--------------------------------------------------------------------------------
/demo/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/test/mailers/.keep
--------------------------------------------------------------------------------
/demo/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/test/models/.keep
--------------------------------------------------------------------------------
/demo/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require File.expand_path('../../config/environment', __FILE__)
3 | require 'rails/test_help'
4 |
5 | module ActiveSupport
6 | class TestCase
7 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
8 | #
9 | # Note: You'll currently still have to declare fixtures explicitly in integration tests
10 | # -- they do not yet inherit this setting
11 | fixtures :all
12 |
13 | # Add more helper methods to be used by all tests here...
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/demo/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/demo/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliyun-beta/aliyun-oss-ruby-sdk/c047ff3062b330c6fe2c53217fa9f6ab1d11c79e/demo/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------
/lib/aliyun/oss.rb:
--------------------------------------------------------------------------------
1 | require 'aliyun/oss/version'
2 | require 'aliyun/oss/struct'
3 | require 'aliyun/oss/error'
4 |
5 | module Aliyun
6 | module Oss
7 | autoload :Utils, 'aliyun/oss/utils'
8 | autoload :Client, 'aliyun/oss/client'
9 | autoload :Authorization, 'aliyun/oss/authorization'
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/api/bucket_multiparts.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Api
4 | module BucketMultiparts
5 | # Initialize a Multipart Upload event, before using Multipart Upload mode to transmit data, we has to call the interface to notify the OSS initialize a Multipart Upload events.
6 | #
7 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/multipart-upload&InitiateMultipartUpload Initiate Multipart Upload
8 | #
9 | # @param key [String] object name
10 | # @param headers [Hash] headers
11 | # @option headers [String] :Content-Type ('application/x-www-form-urlencoded') Specify Content-Type for the object
12 | # @option headers [String] :Cache-Control Specify the caching behavior when download from browser, ref https://www.ietf.org/rfc/rfc2616.txt?spm=5176.730001.3.128.Y5W4bu&file=rfc2616.txt RFC2616}
13 | # @option headers [String] :Content-Disposition Specify the name when download, ref https://www.ietf.org/rfc/rfc2616.txt?spm=5176.730001.3.128.Y5W4bu&file=rfc2616.txt RFC2616}
14 | # @option headers [String] :Content-Encoding Specify the content encoding when download, ref https://www.ietf.org/rfc/rfc2616.txt?spm=5176.730001.3.128.Y5W4bu&file=rfc2616.txt RFC2616}
15 | # @option headers [Integer] :Expires Specify the expiration time (milliseconds)
16 | # @option headers [String] :x-oss-server-side-encryption Specify the oss server-side encryption algorithm when the object was created. supported value: 'AES256'#
17 | #
18 | # @return [Response]
19 | def bucket_init_multipart(key, headers = {})
20 | Utils.stringify_keys!(headers)
21 | query = { 'uploads' => true }
22 | http.post("/#{key}", query: query, headers: headers, bucket: bucket, key: key)
23 | end
24 |
25 | # Upload object in part.
26 | #
27 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/multipart-upload&UploadPart Upload Part
28 | #
29 | # @param key [String] object name
30 | # @param number [Integer] the part number, Range in 1~10000.
31 | # @param upload_id [String] the upload ID return by #bucket_init_multipart
32 | # @param file [File, bin data] the upload data
33 | #
34 | # @raise [RequestError]
35 | # @raise [MultipartPartNumberEmptyError]
36 | # @raise [MultipartUploadIdEmptyError]
37 | #
38 | # @return [Response]
39 | def bucket_multipart_upload(upload_id, key, number, file)
40 | fail MultipartPartNumberEmptyError if number.nil?
41 | fail MultipartUploadIdEmptyError if upload_id.nil? || upload_id.empty?
42 |
43 | query = { 'partNumber' => number.to_s, 'uploadId' => upload_id }
44 |
45 | http.put("/#{key}", query: query, body: Utils.to_data(file), bucket: bucket, key: key)
46 | end
47 |
48 | # Upload a Part from an existing Object Copy data.
49 | #
50 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/multipart-upload&UploadPartCopy Upload Part Copy
51 | #
52 | # @param key [String] object name
53 | # @param number [Integer] the part number, Range in 1~10000.
54 | # @param upload_id [String] the upload ID return by #bucket_init_multipart
55 | # @param options [Hash] options
56 | # @option options [String] :source_bucket the source bucket name
57 | # @option options [String] :source_key the source object name
58 | # @option options [String] :range the Range bytes, not set means the whole object, eg: bytes=100-6291756
59 | # @option options [String] :x-oss-copy-source-if-match If the specified ETag match the source object ETag, normal transfer and return 200; Otherwise return 412(precondition)
60 | # @option options [String] :x-oss-copy-source-if-none-match If the specified ETag not match the source object ETag, normal transfer and return 200; Otherwise return 304(Not Modified)
61 | # @option options [String] :x-oss-copy-source-if-unmodified-since If the specified time is equal to or later than the source object last modification time, normal transfer ans return 200; Otherwise returns 412(precondition)
62 | # @option options [String] :x-oss-copy-source-if-modified-since If the specified time is earlier than the source object last modification time, normal transfer ans return 200; Otherwise returns 304(not modified)
63 | #
64 | # @raise [RequestError]
65 | # @raise [MultipartSourceBucketEmptyError]
66 | # @raise [MultipartSourceKeyEmptyError]
67 | #
68 | # @return [Response]
69 | def bucket_multipart_copy_upload(upload_id, key, number, options = {})
70 | Utils.stringify_keys!(options)
71 | source_bucket = options.delete('source_bucket').to_s
72 | source_key = options.delete('source_key').to_s
73 | range = options.delete('range')
74 |
75 | fail MultipartSourceBucketEmptyError if source_bucket.empty?
76 | fail MultipartSourceKeyEmptyError if source_key.empty?
77 |
78 | query = { 'partNumber' => number, 'uploadId' => upload_id }
79 | headers = copy_upload_headers(source_bucket, source_key, range, options)
80 |
81 | http.put("/#{key}", query: query, headers: headers, bucket: bucket, key: key)
82 | end
83 |
84 | # Complete a Multipart Upload event.
85 | #
86 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/multipart-upload&CompleteMultipartUpload Complete Multipart Upload
87 | #
88 | # @param key [String] object name
89 | # @param upload_id [String] the upload ID return by #bucket_init_multipart
90 | # @param parts [Array] parts
91 | #
92 | # @raise [RequestError]
93 | # @raise [MultipartPartsEmptyError]
94 | # @raise [MultipartUploadIdEmptyError]
95 | #
96 | # @return [Response]
97 | def bucket_complete_multipart(upload_id, key, parts = [])
98 | fail MultipartPartsEmptyError if parts.nil? || parts.empty?
99 | fail MultipartUploadIdEmptyError if upload_id.nil?
100 |
101 | query = { 'uploadId' => upload_id }
102 |
103 | body = XmlGenerator.generate_complete_multipart_xml(parts)
104 |
105 | http.post("/#{key}", query: query, body: body, bucket: bucket, key: key)
106 | end
107 |
108 | # Abort a Multipart Upload event
109 | #
110 | # @note After abort the Multipart Upload, the Uploaded data will be deleted
111 | # @note When abort a Multipart Upload event, if there are still part upload belonging to this event, then theree parts will not be removed. So if there is a concurrent access, in order to release the space on the OSS completely, you need to call #bucket_abort_multipart a few times.
112 | #
113 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/multipart-upload&AbortMultipartUpload Abort Multipart Upload
114 | #
115 | # @param key [String] the object name
116 | # @param upload_id [String] the upload ID return by #bucket_init_multipart
117 | #
118 | # @raise [RequestError]
119 | #
120 | # @return [Response]
121 | def bucket_abort_multipart(upload_id, key)
122 | query = { 'uploadId' => upload_id }
123 | http.delete("/#{key}", query: query, bucket: bucket, key: key)
124 | end
125 |
126 | # List existing opened Multipart Upload event.
127 | #
128 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/multipart-upload&ListMultipartUploads List Multipart Uploads
129 | #
130 | # @param options [Hash] options
131 | # @option options [String] :prefix Filter objects with prefix
132 | # @option options [String] :delimiter Used to group objects with delimiter
133 | # @option options [Integer] :max-uploads (1000) Limit number of Multipart Upload events, the maxinum should <= 1000
134 | # @option options [String] :encoding-type Encoding type used for unsupported character
135 | # @option options [String] :key-marker with upload-id-marker used to specify the result range.
136 | # @option options [String] :upload-id-marker with key-marker used to specify the result range.
137 | #
138 | # @return [Response]
139 | def bucket_list_multiparts(options = {})
140 | Utils.stringify_keys!(options)
141 | accepted_keys = ['prefix', 'key-marker', 'upload-id-marker', 'max-uploads', 'delimiter', 'encoding-type']
142 |
143 | query = Utils.hash_slice(options, *accepted_keys)
144 | .merge('uploads' => true)
145 |
146 | http.get('/', query: query, bucket: bucket)
147 | end
148 |
149 | # List uploaded parts for Multipart Upload event
150 | #
151 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/multipart-upload&ListParts List Parts
152 | #
153 | # @param key [String] the object name
154 | # @param upload_id [Integer] the upload ID return by #bucket_init_multipart
155 | # @param options [Hash] options
156 | # @option options [Integer] :max-parts (1000) Limit number of parts, the maxinum should <= 1000
157 | # @option options [Integer] :part-number-marker Specify the start part, return parts which number large than the specified value
158 | # @option options [String] :encoding-type Encoding type used for unsupported character in xml 1.0
159 | #
160 | # @return [Response]
161 | def bucket_list_parts(upload_id, key, options = {})
162 | Utils.stringify_keys!(options)
163 | accepted_keys = ['max-parts', 'part-number-marker', 'encoding-type']
164 |
165 | query = Utils.hash_slice(options, *accepted_keys).merge('uploadId' => upload_id)
166 |
167 | http.get("/#{key}", query: query, bucket: bucket, key: key)
168 | end
169 |
170 | private
171 |
172 | def copy_upload_headers(source_bucket, source_key, range, options)
173 | copy_source = "/#{source_bucket}/#{source_key}"
174 |
175 | headers = {}
176 | headers.merge!('x-oss-copy-source' => copy_source)
177 | headers.merge!('x-oss-copy-source-range' => range) if range
178 | headers.merge!(options)
179 | headers
180 | end
181 | end
182 | end
183 | end
184 | end
185 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/api/bucket_property.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Api
4 | module BucketProperty
5 | # Used to modify the bucket access.
6 | #
7 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&PutBucketACL Put Bucket Acl
8 | #
9 | # @param acl [String] supported value: public-read-write | public-read | private
10 | # @raise [RequestError]
11 | #
12 | # @return [Response]
13 | def bucket_set_acl(acl)
14 | query = { 'acl' => true }
15 | headers = { 'x-oss-acl' => acl }
16 | http.put('/', query: query, headers: headers, bucket: bucket)
17 | end
18 |
19 | # Used to enable access logging.
20 | #
21 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&PutBucketLogging Put Bucket Logging
22 | #
23 | # @param target_bucket [String] specifies the bucket where you want Aliyun OSS to store server access logs.
24 | # @param target_prefix [String] this element lets you specify a prefix for the objects that the log files will be stored.
25 | #
26 | # @raise [RequestError]
27 | #
28 | # @return [Response]
29 | def bucket_enable_logging(target_bucket, target_prefix = nil)
30 | query = { 'logging' => true }
31 |
32 | body = XmlGenerator.generate_enable_logging_xml(target_bucket,
33 | target_prefix)
34 |
35 | http.put('/', query: query, body: body, bucket: bucket)
36 | end
37 |
38 | # Used to disable access logging.
39 | #
40 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&DeleteBucketLogging Delete Bucket Logging
41 | #
42 | # @raise [RequestError]
43 | #
44 | # @return [Response]
45 | def bucket_disable_logging
46 | query = { 'logging' => false }
47 | http.delete('/', query: query, bucket: bucket)
48 | end
49 |
50 | # Used to enable static website hosted mode.
51 | #
52 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&PutBucketWebsite Put Bucket Website
53 | #
54 | # @param suffix [String] A suffix that is appended to a request that is for a directory on the website endpoint (e.g. if the suffix is index.html and you make a request to samplebucket/images/ the data that is returned will be for the object with the key name images/index.html) The suffix must not be empty and must not include a slash character.
55 | # @param key [String] The object key name to use when a 4XX class error occurs
56 | #
57 | # @raise [RequestError]
58 | #
59 | # @return [Response]
60 | def bucket_enable_website(suffix, key = nil)
61 | query = { 'website' => true }
62 |
63 | body = XmlGenerator.generate_enable_website_xml(suffix, key)
64 |
65 | http.put('/', query: query, body: body, bucket: bucket)
66 | end
67 |
68 | # Used to disable website hostted mode.
69 | #
70 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&DeleteBucketWebsite Delete Bucket Website
71 | #
72 | # @raise [RequestError]
73 | #
74 | # @return [Response]
75 | def bucket_disable_website
76 | query = { 'website' => false }
77 | http.delete('/', query: query, bucket: bucket)
78 | end
79 |
80 | # Used to set referer for bucket.
81 | #
82 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&PutBucketReferer Put Bucket Referer
83 | #
84 | # @param referers [Array] white list for allowed referer.
85 | # @param allowed_empty [Boolean] whether allow empty refer.
86 | #
87 | # @raise [RequestError]
88 | #
89 | # @return [Response]
90 | def bucket_set_referer(referers = [], allowed_empty = false)
91 | query = { 'referer' => true }
92 |
93 | body = XmlGenerator.generate_set_referer_xml(referers, allowed_empty)
94 |
95 | http.put('/', query: query, body: body, bucket: bucket)
96 | end
97 |
98 | # Used to enable and set lifecycle for bucket
99 | #
100 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&PutBucketLifecycle Put Bucket Lifecycle
101 | #
102 | # @param rules [Array] rules for lifecycle
103 | #
104 | # @raise [RequestError]
105 | # @raise [Aliyun::Oss::InvalidLifeCycleRuleError]
106 | # if rule invalid
107 | #
108 | # @return [Response]
109 | def bucket_enable_lifecycle(rules = [])
110 | query = { 'lifecycle' => true }
111 |
112 | rules = Utils.wrap(rules)
113 |
114 | rules.each do |rule|
115 | unless rule.valid?
116 | fail Aliyun::Oss::InvalidLifeCycleRuleError, rule.inspect
117 | end
118 | end
119 |
120 | body = XmlGenerator.generate_lifecycle_rules(rules)
121 |
122 | http.put('/', query: query, body: body, bucket: bucket)
123 | end
124 |
125 | # Used to disable lifecycle for bucket.
126 | #
127 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&DeleteBucketLifecycle Delete Bucket Lifecycle
128 | def bucket_disable_lifecycle
129 | query = { 'lifecycle' => false }
130 | http.delete('/', query: query, bucket: bucket)
131 | end
132 |
133 | # Used to enable CORS and set rules for bucket
134 | #
135 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/cors&PutBucketcors Put Bucket cors
136 | #
137 | # @param rules [Array] array of rule
138 | #
139 | # @raise [RequestError]
140 | # @raise [InvalidCorsRule]
141 | # if rule invalid
142 | #
143 | # @return [Response]
144 | def bucket_enable_cors(rules = [])
145 | query = { 'cors' => true }
146 |
147 | rules = Utils.wrap(rules)
148 |
149 | rules.each do |rule|
150 | unless rule.valid?
151 | fail Aliyun::Oss::InvalidCorsRuleError, rule.inspect
152 | end
153 | end
154 |
155 | body = XmlGenerator.generate_cors_rules(rules)
156 |
157 | http.put('/', query: query, body: body, bucket: bucket)
158 | end
159 |
160 | # Used to disable cors and clear rules for bucket
161 | #
162 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/cors&DeleteBucketcors Delete Bucket cors
163 | #
164 | # @raise [RequestError]
165 | #
166 | # @return [Response]
167 | def bucket_disable_cors
168 | query = { 'cors' => false }
169 | http.delete('/', query: query, bucket: bucket)
170 | end
171 |
172 | # Get ACL for bucket
173 | #
174 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&GetBucketAcl Get Bucket ACL
175 | #
176 | # @return [Response]
177 | def bucket_get_acl
178 | query = { 'acl' => true }
179 | http.get('/', query: query, bucket: bucket)
180 | end
181 |
182 | # Get the location information of the Bucket's data center
183 | #
184 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&GetBucketLocation Get Bucket Location
185 | #
186 | # @return [Response]
187 | def bucket_get_location
188 | query = { 'location' => true }
189 | http.get('/', query: query, bucket: bucket)
190 | end
191 |
192 | # Get the log configuration of Bucket
193 | #
194 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&GetBucketLogging Get Bucket Logging
195 | #
196 | # @raise [RequestError]
197 | #
198 | # @return [Response]
199 | def bucket_get_logging
200 | query = { 'logging' => true }
201 | http.get('/', query: query, bucket: bucket)
202 | end
203 |
204 | # Get the bucket state of static website hosting.
205 | #
206 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&GetBucketWebsite Get Bucket Website
207 | #
208 | # @return [Response]
209 | def bucket_get_website
210 | query = { 'website' => true }
211 | http.get('/', query: query, bucket: bucket)
212 | end
213 |
214 | # Get the referer configuration of bucket
215 | #
216 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&GetBucketReferer Get Bucket Referer
217 | #
218 | # @return [Response]
219 | def bucket_get_referer
220 | query = { 'referer' => true }
221 | http.get('/', query: query, bucket: bucket)
222 | end
223 |
224 | # Get the lifecycle configuration of bucket
225 | #
226 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&GetBucketLifecycle Get Bucket Lifecycle
227 | #
228 | # @return [Response]
229 | def bucket_get_lifecycle
230 | query = { 'lifecycle' => true }
231 | http.get('/', query: query, bucket: bucket)
232 | end
233 |
234 | # Get the CORS rules of bucket
235 | #
236 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/cors&GetBucketcors Get Bucket cors
237 | #
238 | # @return [Response]
239 | def bucket_get_cors
240 | query = { 'cors' => true }
241 | http.get('/', query: query, bucket: bucket)
242 | end
243 | end
244 | end
245 | end
246 | end
247 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/api/buckets.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Api
4 | module Buckets
5 | # List buckets
6 | #
7 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/service&GetService GetService (ListBucket)
8 | #
9 | # @param options [Hash] options
10 | # @option options [String] :prefix Filter buckets with prefix
11 | # @option options [String] :marker Bucket name should after marker in alphabetical order
12 | # @option options [Integer] :max-keys (100) Limit number of buckets, the maxinum should <= 1000
13 | #
14 | # @raise [RequestError]
15 | #
16 | # @return [Response]
17 | def list_buckets(options = {})
18 | Utils.stringify_keys!(options)
19 | query = Utils.hash_slice(options, 'prefix', 'marker', 'max-keys')
20 | http.get('/', query: query)
21 | end
22 |
23 | # Create bucket
24 | #
25 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&PutBucket Put Bucket
26 | #
27 | # @example
28 | # oss.client.bucket_create('oss-sdk-dev-hangzhou-xxx')
29 | #
30 | # @param name [String] Specify bucket name
31 | # @param location [String] Specify the bucket's data center location, can be one of below:
32 | # oss-cn-hangzhou,oss-cn-qingdao,oss-cn-beijing,oss-cn-hongkong,
33 | # oss-cn-shenzhen,oss-cn-shanghai,oss-us-west-1 ,oss-ap-southeast-1
34 | # @param acl [String] Specify the bucket's access. {Aliyun::Oss::Api::BucketProperty#bucket_set_acl}
35 | #
36 | # @raise [RequestError]
37 | #
38 | # @return [Response]
39 | def bucket_create(name, location = 'oss-cn-hangzhou', acl = 'private')
40 | query = { 'acl' => true }
41 | headers = { 'x-oss-acl' => acl }
42 |
43 | body = XmlGenerator.generate_create_bucket_xml(location)
44 |
45 | http.put('/', query: query, headers: headers, body: body, bucket: name, location: location)
46 | end
47 |
48 | # Delete bucket
49 | #
50 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/bucket&DeleteBucket Delete Bucket
51 | #
52 | # @param name [String] bucket name want to delete
53 | #
54 | # @raise [RequestError]
55 | #
56 | # @return [Response]
57 | def bucket_delete(name)
58 | http.delete('/', bucket: name)
59 | end
60 |
61 | # OPTIONS Object
62 | #
63 | # @see https://docs.aliyun.com/#/pub/oss/api-reference/cors&OptionObject OPTIONS Object
64 | #
65 | # @param object_key [String] the object name want to visit.
66 | # @param origin [String] the requested source domain, denoting cross-domain request.
67 | # @param request_method [String] the actual request method will be used.
68 | # @param request_headers [Array] the actual used headers except simple headers will be used.
69 | #
70 | # @raise [RequestError]
71 | #
72 | # @return [Response]
73 | def bucket_preflight(object_key, origin, request_method, request_headers = [])
74 | path = object_key ? "/#{object_key}" : '/'
75 |
76 | headers = {
77 | 'Origin' => origin,
78 | 'Access-Control-Request-Method' => request_method
79 | }
80 |
81 | unless request_headers.empty?
82 | value = request_headers.join(',')
83 | headers.merge!('Access-Control-Request-Headers' => value)
84 | end
85 |
86 | http.options(path, headers: headers, bucket: bucket, key: object_key)
87 | end
88 | end
89 | end
90 | end
91 | end
92 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/authorization.rb:
--------------------------------------------------------------------------------
1 | require 'base64'
2 | require 'openssl'
3 | require 'digest'
4 | require 'json'
5 | require 'cgi'
6 |
7 | module Aliyun
8 | module Oss
9 | class Authorization
10 | PROVIDER = 'OSS'
11 | OVERRIDE_RESPONSE_LIST = %w(
12 | response-content-type response-content-language response-cache-control
13 | logging response-content-encoding acl uploadId uploads partNumber group
14 | link delete website location objectInfo response-expires
15 | response-content-disposition cors lifecycle restore qos referer append
16 | position)
17 |
18 | # Get temporary Signature
19 | #
20 | # @see {https://docs.aliyun.com/#/pub/oss/api-reference/access-control&signature-url Tempoorary Signature}
21 | #
22 | # @param secret_key [String] Secret Key
23 | # @param expire_time [Integer] the number of seconds since January 1, 1970 UTC. used to specified expired time
24 | # @param [Hash] options other options
25 | # @option options [String] :key the object name
26 | # @option options [String] :bucket bucket name
27 | # @option options [String] :verb, Request Method
28 | # @option options [Hash] :query Query Params
29 | # @option options [Hash] :headers Headers Params
30 | #
31 | # @return [String]
32 | def self.get_temporary_signature(secret_key, expire_time, options = {})
33 | content_string = concat_content_string(options[:verb], expire_time, options)
34 | CGI.escape(signature(secret_key, content_string).strip)
35 | end
36 |
37 | # Get base64 encoded string, used to fill policy field
38 | #
39 | # @see {https://docs.aliyun.com/#/pub/oss/api-reference/object&PostObject Post Object}
40 | #
41 | # @param policy [Hash] Policy {https://docs.aliyun.com/#/pub/oss/api-reference/object&PostObject#menu7 Detail}
42 | #
43 | # @return [String]
44 | def self.get_base64_policy(policy)
45 | Base64.encode64(JSON.generate(policy).force_encoding('utf-8')).delete("\n")
46 | end
47 |
48 | # Get Signature for policy
49 | #
50 | # @see {https://docs.aliyun.com/#/pub/oss/api-reference/object&PostObject}
51 | #
52 | # @param secret_key [String] Secret Key
53 | # @param policy [Hash] Policy {https://docs.aliyun.com/#/pub/oss/api-reference/object&PostObject#menu7 Detail}
54 | #
55 | # @return [String]
56 | def self.get_policy_signature(secret_key, policy)
57 | signature(secret_key, get_base64_policy(policy)).strip
58 | end
59 |
60 | # @private
61 | #
62 | # Get authorization key
63 | #
64 | # @see {https://docs.aliyun.com/#/pub/oss/api-reference/access-control&signature-header Authorization}
65 | #
66 | # @param access_key [String] Access Key
67 | # @param secret_key [String] Secret Key
68 | # @param options [Hash] Options
69 | # @option options [String] :verb VERB, request method
70 | # @option options [String] :date Request Time in formate: '%a, %d %b %Y %H:%M:%S GMT'
71 | # @option options [String] :bucket Bucket Name
72 | # @option options [String] :key Object Name
73 | # @option options [Hash] :query Query key-value pair
74 | # @option options [Hash] :headers Headers
75 | #
76 | # @return [String] the authorization string
77 | def self.get_authorization(access_key, secret_key, options = {})
78 | content_string = concat_content_string(options[:verb], options[:date], options)
79 | signature_string = signature(secret_key, content_string)
80 | "#{PROVIDER} #{access_key}:#{signature_string.strip}"
81 | end
82 |
83 | def self.concat_content_string(verb, time, options = {})
84 | headers = options.fetch(:headers, {})
85 |
86 | conon_headers = get_cononicalized_oss_headers(headers)
87 | conon_resource = get_cononicalized_resource(
88 | *options.values_at(:bucket, :key, :query)
89 | )
90 |
91 | join_values(verb, time, headers, conon_headers, conon_resource)
92 | end
93 |
94 | def self.join_values(verb, time, headers, conon_headers, conon_resource)
95 | [
96 | verb,
97 | headers['Content-MD5'].to_s.strip,
98 | headers['Content-Type'].to_s.strip,
99 | time,
100 | conon_headers
101 | ].join("\n") + conon_resource
102 | end
103 |
104 | def self.signature(secret_key, content_string)
105 | utf8_string = content_string.force_encoding('utf-8')
106 | Base64.encode64(
107 | OpenSSL::HMAC.digest(
108 | OpenSSL::Digest::SHA1.new,
109 | secret_key,
110 | utf8_string
111 | )
112 | )
113 | end
114 |
115 | def self.get_cononicalized_oss_headers(headers)
116 | oss_headers = (headers || {}).select do |key, _|
117 | key.to_s.downcase.start_with?('x-oss-')
118 | end
119 | return if oss_headers.empty?
120 |
121 | oss_headers.keys.sort.map do |key|
122 | "#{key.downcase}:#{oss_headers[key]}"
123 | end.join("\n") + "\n"
124 | end
125 |
126 | def self.get_cononicalized_resource(bucket, key, query)
127 | conon_resource = '/'
128 | conon_resource += "#{bucket}/" if bucket
129 | conon_resource += key if key
130 | return conon_resource if query.nil? || query.empty?
131 |
132 | query_str = query.keys.select { |k| OVERRIDE_RESPONSE_LIST.include?(k) }
133 | .sort.map { |k| "#{k}=#{query[k]}" }.join('&')
134 |
135 | query_str.empty? ? conon_resource : conon_resource + '?' + query_str
136 | end
137 | end
138 | end
139 | end
140 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/client.rb:
--------------------------------------------------------------------------------
1 | require 'aliyun/oss/xml_generator'
2 | # Function Based
3 | require 'aliyun/oss/api/buckets'
4 | require 'aliyun/oss/api/bucket_property'
5 | require 'aliyun/oss/api/bucket_objects'
6 | require 'aliyun/oss/api/bucket_multiparts'
7 | # Object Based
8 | require 'aliyun/oss/client/clients'
9 |
10 | require 'aliyun/oss/http'
11 |
12 | module Aliyun
13 | module Oss
14 | class Client
15 | include Aliyun::Oss::Api::Buckets
16 | include Aliyun::Oss::Api::BucketProperty
17 | include Aliyun::Oss::Api::BucketObjects
18 | include Aliyun::Oss::Api::BucketMultiparts
19 |
20 | attr_reader :access_key, :secret_key, :bucket
21 |
22 | # Initialize a object
23 | #
24 | # @example
25 | # Aliyun::Oss::Client.new("ACCESS_KEY", "SECRET_KEY", host: "oss-cn-beijing.aliyuncs.com", bucket: 'oss-sdk-beijing')
26 | #
27 | # @param access_key [String] access_key obtained from aliyun
28 | # @param secret_key [String] secret_key obtained from aliyun
29 | # @option options [String] :host host for bucket's data center
30 | # @option options [String] :bucket Bucket name
31 | #
32 | # @return [Response]
33 | def initialize(access_key, secret_key, options = {})
34 | @access_key = access_key
35 | @secret_key = secret_key
36 | @options = options
37 | @bucket = options[:bucket]
38 |
39 | @services = {}
40 | end
41 |
42 | private
43 |
44 | def http
45 | @http ||= Http.new(access_key, secret_key, @options[:host])
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/client/bucket_multiparts.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | class Client
4 | module BucketMultiparts
5 | # Init a Multipart Upload Event
6 | #
7 | # @see Api::BucketMultiparts#bucket_init_multipart
8 | # @example (see Api::BucketMultiparts#bucket_init_multipart)
9 | # @param (see Api::BucketMultiparts#bucket_init_multipart)
10 | # @raise (see Api::BucketMultiparts#bucket_init_multipart)
11 | #
12 | # @return [Struct::Multipart]
13 | def init(*args)
14 | result = client.bucket_init_multipart(*args).parsed_response
15 |
16 | multipart = Utils.dig_value(result, 'InitiateMultipartUploadResult')
17 | Struct::Multipart.new((multipart || {}).merge(client: client))
18 | end
19 |
20 | # List exist Multipart Upload Events of bucket
21 | #
22 | # @see Api::BucketMultiparts#bucket_list_multiparts
23 | # @example (see Api::BucketMultiparts#bucket_list_multiparts)
24 | # @param (see Api::BucketMultiparts#bucket_list_multiparts)
25 | # @raise (see Api::BucketMultiparts#bucket_list_multiparts)
26 | #
27 | # @return [Array]
28 | def list(*args)
29 | result = client.bucket_list_multiparts(*args).parsed_response
30 |
31 | multipart_keys = %w(ListMultipartUploadsResult Upload)
32 | Utils.wrap(Utils.dig_value(result, *multipart_keys)).map do |multipart|
33 | Struct::Multipart.new(multipart.merge(client: client))
34 | end
35 | end
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/client/bucket_objects.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | class Client
4 | module BucketObjects
5 | # List objects of bucket
6 | #
7 | # @see Api::BucketObjects#bucket_list_objects
8 | # @example (see Api::BucketObjects#bucket_list_objects)
9 | # @param (see Api::BucketObjects#bucket_list_objects)
10 | # @raise (see Api::BucketObjects#bucket_list_objects)
11 | #
12 | # @return [Array]
13 | def list(*args)
14 | result = client.bucket_list_objects(*args).parsed_response
15 |
16 | object_keys = %w(ListBucketResult Contents)
17 | directory_keys = %w(ListBucketResult CommonPrefixes)
18 | Struct::Object.init_from_response(result, object_keys, client) + \
19 | Struct::Object.init_from_response(result, directory_keys, client)
20 | end
21 |
22 | # create object of bucket
23 | #
24 | # @see Api::BucketObjects#bucket_create_object
25 | # @example (see Api::BucketObjects#bucket_create_object)
26 | # @param (see Api::BucketObjects#bucket_create_object)
27 | # @raise (see Api::BucketObjects#bucket_create_object)
28 | #
29 | # @return [true]
30 | def create(*args)
31 | !!client.bucket_create_object(*args)
32 | end
33 |
34 | # Delete object for bucket
35 | #
36 | # @see Api::BucketObjects#bucket_delete_object
37 | # @example (see Api::BucketObjects#bucket_delete_object)
38 | # @param (see Api::BucketObjects#bucket_delete_object)
39 | # @raise (see Api::BucketObjects#bucket_delete_object)
40 | #
41 | # @return [true]
42 | def delete(*args)
43 | !!client.bucket_delete_object(*args)
44 | end
45 |
46 | # Delete objects for bucket
47 | #
48 | # @see Api::BucketObjects#bucket_delete_objects
49 | # @example (see Api::BucketObjects#bucket_delete_objects)
50 | # @param (see Api::BucketObjects#bucket_delete_objects)
51 | # @raise (see Api::BucketObjects#bucket_delete_objects)
52 | #
53 | # @return [true]
54 | def delete_multiple(*args)
55 | !!client.bucket_delete_objects(*args)
56 | end
57 |
58 | # Copy from existing object
59 | #
60 | # @see Api::BucketObjects#bucket_copy_object
61 | # @example (see Api::BucketObjects#bucket_copy_object)
62 | # @param (see Api::BucketObjects#bucket_copy_object)
63 | # @raise (see Api::BucketObjects#bucket_copy_object)
64 | #
65 | # @return [true]
66 | def copy(*args)
67 | !!client.bucket_copy_object(*args)
68 | end
69 |
70 | # Get Object
71 | #
72 | # @see Api::BucketObjects#bucket_get_object
73 | # @example (see Api::BucketObjects#bucket_get_object)
74 | # @param (see Api::BucketObjects#bucket_get_object)
75 | # @raise (see Api::BucketObjects#bucket_get_object)
76 | #
77 | # @return [BodyString]
78 | def get(*args)
79 | client.bucket_get_object(*args).body
80 | end
81 |
82 | # Append data to a object, will create Appendable object
83 | #
84 | # @see Api::BucketObjects#bucket_append_object
85 | # @example (see Api::BucketObjects#bucket_append_object)
86 | # @param (see Api::BucketObjects#bucket_append_object)
87 | # @raise (see Api::BucketObjects#bucket_append_object)
88 | #
89 | # @return [HTTParty::Response::Headers]
90 | def append(*args)
91 | client.bucket_append_object(*args).headers
92 | end
93 | end
94 | end
95 | end
96 | end
97 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/client/buckets.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | class Client
4 | module Buckets
5 | # List buckets
6 | #
7 | # @see Api::Buckets#list_buckets
8 | # @example (see Api::Buckets#list_buckets)
9 | # @param (see Api::Buckets#list_buckets)
10 | # @raise (see Api::Buckets#list_buckets)
11 | #
12 | # @return [Array]
13 | def list(options = {})
14 | result = client.list_buckets(options).parsed_response
15 |
16 | bucket_keys = %w(ListAllMyBucketsResult Buckets Bucket)
17 | Utils.wrap(Utils.dig_value(result, *bucket_keys)).map do |bucket_hash|
18 | build_bucket(bucket_hash, client)
19 | end
20 | end
21 |
22 | # Create bucket
23 | #
24 | # @see Api::Buckets#bucket_create
25 | # @example (see Api::Buckets#bucket_create)
26 | # @param (see Api::Buckets#bucket_create)
27 | # @raise (see Api::Buckets#bucket_create)
28 | #
29 | # @return [true]
30 | def create(*args)
31 | !!client.bucket_create(*args)
32 | end
33 |
34 | # Delete bucket
35 | #
36 | # @see Api::Buckets#bucket_delete
37 | # @example (see Api::Buckets#bucket_delete)
38 | # @param (see Api::Buckets#bucket_delete)
39 | # @raise (see Api::Buckets#bucket_delete)
40 | #
41 | # @return [true]
42 | def delete(*args)
43 | !!client.bucket_delete(*args)
44 | end
45 |
46 | private
47 |
48 | def build_bucket(bucket_hash, client)
49 | Struct::Bucket.new(bucket_hash).tap do |bucket|
50 | bucket.client = Client.new(
51 | client.access_key, client.secret_key, host: bucket.host, bucket: bucket.name
52 | )
53 | end
54 | end
55 | end
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/client/clients.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | #
4 | # Here is some services used to make object based API possible, they are all contains a reference to instance of client, which used to do the real job.
5 | #
6 | # buckets: used to do many buckets operations eg: #list, #create, #delete
7 | #
8 | # client.buckets
9 | #
10 | # bucket_objects: used to do some operation on objects eg: #list, #create, :delete, #copy
11 | #
12 | # client.bucket_objects
13 | #
14 | # bucket_multiparts: used to do some operation for multiparts eg: #init, #list
15 | #
16 | # client.bucket_multiparts
17 | #
18 | # current_bucket: get current bucket
19 | #
20 | # client.current_bucket
21 | #
22 | #
23 | class Client
24 | def buckets
25 | @services[:buckets] ||= Client::BucketsService.new(self)
26 | end
27 |
28 | def bucket_objects
29 | @services[:bucket_objects] ||= Client::BucketObjectsService.new(self)
30 | end
31 |
32 | def bucket_multiparts
33 | @services[:bucket_multiparts] ||= \
34 | Client::BucketMultipartsService.new(self)
35 | end
36 |
37 | def current_bucket
38 | @services[:current_bucket] ||= \
39 | Aliyun::Oss::Struct::Bucket.new(name: bucket, client: self)
40 | end
41 |
42 | ClientService = ::Struct.new(:client)
43 |
44 | require 'aliyun/oss/client/buckets'
45 |
46 | class BucketsService < ClientService
47 | include Client::Buckets
48 | end
49 |
50 | require 'aliyun/oss/client/bucket_objects'
51 |
52 | class BucketObjectsService < ClientService
53 | include Client::BucketObjects
54 | end
55 |
56 | require 'aliyun/oss/client/bucket_multiparts'
57 |
58 | class BucketMultipartsService < ClientService
59 | include Client::BucketMultiparts
60 | end
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/error.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | class Error < StandardError; end
4 |
5 | # [Aliyun::Oss::RequestError] when OSS give a Non 2xx response
6 | class RequestError < Error
7 | # Error Code defined by OSS
8 | attr_reader :code
9 |
10 | # Error Message defined by OSS
11 | attr_reader :message
12 |
13 | # It's the UUID to uniquely identifies this request;
14 | # When you can't solve the problem, you can request help from the OSS development engineer with the RequestId.
15 | attr_reader :request_id
16 |
17 | # The Origin Httparty Response
18 | attr_reader :origin_response
19 |
20 | def initialize(response)
21 | if (error_values = response.parsed_response['Error']).empty?
22 | @code = response.code
23 | @message = response.message
24 | else
25 | @code = error_values['Code']
26 | @message = error_values['Message']
27 | end
28 | @request_id = response.headers['x-oss-request-id']
29 | @origin_response = response
30 | super("#{@request_id} - #{@code}: #{@message}")
31 | end
32 | end
33 |
34 | class MultipartPartNumberEmpty < Error; end
35 | class MultipartUploadIdEmpty < Error; end
36 | class MultipartSourceBucketEmptyError < Error; end
37 | class MultipartSourceKeyEmptyError < Error; end
38 | class MultipartPartsEmptyError < Error; end
39 |
40 | class InvalidCorsRuleError < Error; end
41 | class InvalidLifeCycleRuleError < Error; end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/http.rb:
--------------------------------------------------------------------------------
1 | require 'httparty'
2 | require 'addressable/uri'
3 | require 'aliyun/oss/error'
4 |
5 | module Aliyun
6 | module Oss
7 | class Http # nodoc
8 | attr_reader :access_key, :secret_key
9 |
10 | def initialize(access_key, secret_key, host)
11 | @access_key = access_key
12 | @secret_key = secret_key
13 | @host = host
14 | end
15 |
16 | def get(path, options = {})
17 | request('GET', path, options)
18 | end
19 |
20 | def put(path, options = {})
21 | headers = default_content_type.merge(options[:headers] || {})
22 | request('PUT', path, options.merge(headers: headers))
23 | end
24 |
25 | def post(path, options = {})
26 | headers = default_content_type.merge(options[:headers] || {})
27 | request('POST', path, options.merge(headers: headers))
28 | end
29 |
30 | def delete(path, options = {})
31 | headers = default_content_type.merge(options[:headers] || {})
32 | request('DELETE', path, options.merge(headers: headers))
33 | end
34 |
35 | def options(path, options = {})
36 | request('OPTIONS', path, options)
37 | end
38 |
39 | def head(path, options = {})
40 | request('HEAD', path, options)
41 | end
42 |
43 | private
44 |
45 | def request(verb, resource, options = {})
46 | query = options.fetch(:query, {})
47 | headers = options.fetch(:headers, {})
48 | body = options.delete(:body)
49 |
50 | append_headers!(headers, verb, body, options)
51 |
52 | path = get_path(headers['Host'], resource)
53 | options = { headers: headers, query: query, body: body, uri_adapter: Addressable::URI }
54 |
55 | wrap(HTTParty.__send__(verb.downcase, path, options))
56 | end
57 |
58 | def wrap(response)
59 | case response.code
60 | when 200..299
61 | response
62 | else
63 | fail RequestError, response
64 | end
65 | end
66 |
67 | def append_headers!(headers, verb, body, options)
68 | append_default_headers!(headers)
69 | append_body_headers!(headers, body)
70 | append_host_headers!(headers, options[:bucket], options[:location])
71 | append_authorization_headers!(headers, verb, options)
72 | end
73 |
74 | def append_default_headers!(headers)
75 | headers.merge!(default_headers)
76 | end
77 |
78 | def append_body_headers!(headers, body)
79 | return headers unless body
80 |
81 | unless headers.key?('Content-MD5')
82 | headers.merge!('Content-MD5' => Utils.md5_digest(body))
83 | end
84 |
85 | return if headers.key?('Content-Length')
86 | headers.merge!('Content-Length' => Utils.content_size(body).to_s)
87 | end
88 |
89 | def append_host_headers!(headers, bucket, location)
90 | headers.merge!('Host' => get_host(bucket, location))
91 | end
92 |
93 | def append_authorization_headers!(headers, verb, options)
94 | auth_key = get_auth_key(
95 | options.merge(verb: verb, headers: headers, date: headers['Date'])
96 | )
97 | headers.merge!('Authorization' => auth_key)
98 | end
99 |
100 | def get_auth_key(options)
101 | Authorization.get_authorization(access_key, secret_key, options)
102 | end
103 |
104 | def default_headers
105 | {
106 | 'User-Agent' => user_agent,
107 | 'Date' => Time.now.utc.strftime('%a, %d %b %Y %H:%M:%S GMT')
108 | }
109 | end
110 |
111 | def get_host(bucket, location)
112 | if location && bucket
113 | "#{bucket}.#{location}.aliyuncs.com"
114 | elsif bucket
115 | "#{bucket}.#{@host}"
116 | else
117 | @host
118 | end
119 | end
120 |
121 | def default_content_type
122 | {
123 | 'Content-Type' => 'application/xml'
124 | }
125 | end
126 |
127 | def api_endpoint(host)
128 | "http://#{host}"
129 | end
130 |
131 | def get_path(host, resource)
132 | fixed = resource.split('/').map { |res| CGI.escape(res) }.join('/')
133 | api_endpoint(host) + fixed
134 | end
135 |
136 | def user_agent
137 | "aliyun-oss-sdk-ruby/#{Aliyun::Oss::VERSION} " \
138 | "(#{RbConfig::CONFIG['host_os']} ruby-#{RbConfig::CONFIG['ruby_version']})"
139 | end
140 | end
141 | end
142 | end
143 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Base
5 | def initialize(attributes = {})
6 | attributes.each do |key, value|
7 | m = "#{Utils.underscore(key)}=".to_sym
8 | send(m, value) if self.respond_to?(m)
9 | end
10 | end
11 | end
12 | end
13 | end
14 | end
15 |
16 | require 'aliyun/oss/struct/bucket'
17 | require 'aliyun/oss/struct/object'
18 | require 'aliyun/oss/struct/multipart'
19 |
20 | require 'aliyun/oss/struct/cors'
21 | require 'aliyun/oss/struct/lifecycle'
22 | require 'aliyun/oss/struct/referer'
23 | require 'aliyun/oss/struct/website'
24 | require 'aliyun/oss/struct/logging'
25 |
26 | require 'aliyun/oss/struct/part'
27 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/bucket.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Bucket < Base
5 | # Bucket Name
6 | attr_accessor :name
7 |
8 | # Bucket Location
9 | attr_accessor :location
10 |
11 | # Createion date of Bucket
12 | attr_accessor :creation_date
13 |
14 | # reference to client
15 | attr_accessor :client
16 |
17 | def host
18 | "#{location}.aliyuncs.com"
19 | end
20 |
21 | # Get the location
22 | #
23 | # @return [String]
24 | #
25 | # @see Api::BucketProperty#bucket_get_location
26 | def location!
27 | result = client.bucket_get_location.parsed_response
28 | Utils.dig_value(result, 'LocationConstraint', '__content__') ||
29 | Utils.dig_value(result, 'LocationConstraint')
30 | end
31 |
32 | # Get Logging configration for bucket
33 | #
34 | # return [true]
35 | #
36 | # @see Api::BucketProperty#bucket_get_logging
37 | def logging!
38 | result = client.bucket_get_logging.parsed_response
39 | Struct::Logging.new(Utils.dig_value(result, 'BucketLoggingStatus'))
40 | end
41 |
42 | # Used to enable access logging.
43 | #
44 | # @see Api::BucketProperty#bucket_enable_logging
45 | # @example (see Api::BucketProperty#bucket_enable_logging)
46 | # @param (see Api::BucketProperty#bucket_enable_logging)
47 | # @raise (see Api::BucketProperty#bucket_enable_logging)
48 | #
49 | # @return [true]
50 | def enable_logging(*args)
51 | !!client.bucket_enable_logging(*args)
52 | end
53 |
54 | # Used to disable access logging.
55 | #
56 | # @param (see #bucket_disable_logging)
57 | #
58 | # @return [true]
59 | #
60 | # @see Api::BucketProperty#bucket_disable_logging
61 | def disable_logging
62 | !!client.bucket_disable_logging
63 | end
64 |
65 | # Get the acl
66 | #
67 | # @return [String]
68 | #
69 | # @see Api::BucketProperty#bucket_get_acl
70 | def acl!
71 | result = client.bucket_get_acl.parsed_response
72 | acl_keys = %w(AccessControlPolicy AccessControlList Grant)
73 | Utils.dig_value(result, *acl_keys)
74 | end
75 |
76 | # Set ACL for bucket
77 | #
78 | # @see Api::BucketProperty#bucket_set_acl
79 | # @example (see Api::BucketProperty#bucket_set_acl)
80 | # @param (see Api::BucketProperty#bucket_set_acl)
81 | # @raise (see Api::BucketProperty#bucket_set_acl)
82 | #
83 | # @return [true]
84 | def set_acl(*args)
85 | !!client.bucket_set_acl(*args)
86 | end
87 |
88 | # Get the CORS
89 | #
90 | # @return [Array]
91 | #
92 | # @see Api::BucketProperty#bucket_get_cors
93 | def cors!
94 | result = client.bucket_get_cors.parsed_response
95 | cors_keys = %w(CORSConfiguration CORSRule)
96 | Utils.wrap(Utils.dig_value(result, *cors_keys)).map do |cors|
97 | Struct::Cors.new(cors)
98 | end
99 | end
100 |
101 | # Set CORS for bucket
102 | #
103 | # @see Api::BucketProperty#bucket_enable_cors
104 | # @example (see Api::BucketProperty#bucket_enable_cors)
105 | # @param (see Api::BucketProperty#bucket_enable_cors)
106 | # @raise (see Api::BucketProperty#bucket_enable_cors)
107 | #
108 | # @return [true]
109 | def enable_cors(*args)
110 | !!client.bucket_enable_cors(*args)
111 | end
112 |
113 | # Disable CORS for bucket
114 | #
115 | # @return [true]
116 | #
117 | # @see Api::BucketProperty#bucket_disable_cors
118 | def disable_cors
119 | !!client.bucket_disable_cors
120 | end
121 |
122 | # Get the website configuration
123 | #
124 | # @return [Aliyun::Oss::Rule::Website]
125 | #
126 | # @see Api::BucketProperty#bucket_get_website
127 | def website!
128 | result = client.bucket_get_website.parsed_response
129 | suffix_keys = %w(WebsiteConfiguration IndexDocument Suffix)
130 | error_keys = %w(WebsiteConfiguration ErrorDocument Key)
131 | Aliyun::Oss::Struct::Website.new(
132 | suffix: Utils.dig_value(result, *suffix_keys),
133 | error_key: Utils.dig_value(result, *error_keys)
134 | )
135 | end
136 |
137 | # Used to enable static website hosted mode.
138 | #
139 | # @see Api::BucketProperty#bucket_enable_website
140 | # @example (see Api::BucketProperty#bucket_enable_website)
141 | # @param (see Api::BucketProperty#bucket_enable_website)
142 | # @raise (see Api::BucketProperty#bucket_enable_website)
143 | #
144 | # @return [true]
145 | def enable_website(*args)
146 | !!client.bucket_enable_website(*args)
147 | end
148 |
149 | # Used to disable website hostted mode.
150 | #
151 | # @return [true]
152 | #
153 | # @see Api::BucketProperty#bucket_disable_website
154 | def disable_website
155 | !!client.bucket_disable_website
156 | end
157 |
158 | # Get the referer configuration
159 | #
160 | # @return [Aliyun::Oss::Struct::Referer]
161 | #
162 | # @see Api::BucketProperty#bucket_get_referer
163 | def referer!
164 | result = client.bucket_get_referer.parsed_response
165 | allow_empty = %w(RefererConfiguration AllowEmptyReferer)
166 | referers = %w(RefererConfiguration RefererList Referer)
167 | Aliyun::Oss::Struct::Referer.new(
168 | allow_empty: Utils.dig_value(result, *allow_empty),
169 | referers: Utils.dig_value(result, *referers)
170 | )
171 | end
172 |
173 | # Used to set referer for bucket.
174 | #
175 | # @see Api::BucketProperty#bucket_set_referer
176 | # @example (see Api::BucketProperty#bucket_set_referer)
177 | # @param (see Api::BucketProperty#bucket_set_referer)
178 | # @raise (see Api::BucketProperty#bucket_set_referer)
179 | #
180 | # @return [true]
181 | def set_referer(*args)
182 | !!client.bucket_set_referer(*args)
183 | end
184 |
185 | # Get the lifecycle configuration
186 | #
187 | # @return [Array allowed_origin,
45 | 'AllowedMethod' => allowed_method
46 | }
47 | attrs.merge!('AllowedHeader' => allowed_header) if value_present?(allowed_header)
48 | attrs.merge!('EsposeHeader' => expose_header) if value_present?(expose_header)
49 | attrs.merge!('MaxAgeSeconds' => max_age_seconds) if max_age_seconds
50 | attrs
51 | end
52 |
53 | def valid?
54 | value_present?(allowed_origin) && value_present?(allowed_method)
55 | end
56 |
57 | private
58 |
59 | def value_present?(value)
60 | value && !value.empty?
61 | end
62 | end
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/directory.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Directory < Object
5 | # prefix in CommonPrefixes is key of Directory object
6 | alias_method :prefix=, :key=
7 |
8 | # List objects under directory
9 | #
10 | # @see Api::BucketObjects#bucket_list_objects
11 | # @example (see Api::BucketObjects#bucket_list_objects)
12 | # @param (see Api::BucketObjects#bucket_list_objects)
13 | # @raise (see Api::BucketObjects#bucket_list_objects)
14 | #
15 | # @return [Array]
16 | def list(options = {})
17 | Utils.stringify_keys!(options)
18 | client.bucket_objects.list(options.merge('prefix' => key))
19 | end
20 |
21 | def file?
22 | false
23 | end
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/file.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class File < Object
5 | def file?
6 | true
7 | end
8 |
9 | # Get object share link
10 | #
11 | # @param expired_in_seconds [Integer] expire after specify seconds
12 | #
13 | # @return [URL]
14 | def share_link(expired_in_seconds)
15 | client.bucket_get_object_share_link(key, expired_in_seconds)
16 | end
17 | end
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/lifecycle.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class LifeCycle < Base
5 | # Rule ID, auto set when not set. [String]
6 | attr_accessor :id
7 |
8 | # Used for filter objects. [String]
9 | attr_accessor :prefix
10 |
11 | # Used for set rule status. [Boolean]
12 | attr_accessor :enabled
13 |
14 | # Set auto delete objects after days since last modified, at least exist one with date [Integer]
15 | attr_accessor :days
16 |
17 | # Set auto auto delete object at given time, at least exist one with days, [Time]
18 | attr_accessor :date
19 |
20 | def status=(status)
21 | @enabled = (status == 'Enabled')
22 | end
23 |
24 | def date=(date)
25 | @date = date.is_a?(String) ? Time.parse(date) : date
26 | end
27 |
28 | def days=(days)
29 | @days = days.to_i
30 | end
31 |
32 | def to_hash
33 | return {} unless valid?
34 |
35 | {
36 | 'ID' => id || '',
37 | 'Prefix' => prefix,
38 | 'Status' => status,
39 | 'Expiration' => expiration
40 | }
41 | end
42 |
43 | def expiration=(expiration)
44 | return unless expiration.is_a?(Hash)
45 |
46 | if expiration.key?('Days')
47 | self.days = expiration['Days']
48 | elsif expiration.key?('Date')
49 | self.date = expiration['Date']
50 | end
51 | end
52 |
53 | def valid?
54 | prefix && (days || date)
55 | end
56 |
57 | private
58 |
59 | def status
60 | enabled ? 'Enabled' : 'Disabled'
61 | end
62 |
63 | def expiration
64 | if date && date.is_a?(Time)
65 | { 'Date' => date.utc.strftime('%Y-%m-%dT00:00:00.000Z') }
66 | elsif days && days.is_a?(Integer)
67 | { 'Days' => days.to_i }
68 | end
69 | end
70 | end
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/logging.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Logging < Base
5 | # Container for logging information. This element and its children are present when logging is enabled; otherwise, this element and its children are absent.
6 | attr_accessor :logging_enabled
7 |
8 | # This element specifies the bucket where server access logs will be delivered.
9 | attr_accessor :target_bucket
10 |
11 | # Specifies the prefix for the keys that the log files are being stored for.
12 | attr_accessor :target_prefix
13 |
14 | def initialize(attributes = {})
15 | @logging_enabled = false
16 | super
17 | end
18 |
19 | def logging_enabled=(logging_enabled)
20 | return @logging_enabled = false unless logging_enabled.is_a?(Hash)
21 |
22 | if logging_enabled.key?('TargetBucket')
23 | @target_bucket = logging_enabled['TargetBucket']
24 | end
25 | if logging_enabled.key?('TargetPrefix')
26 | @target_prefix = logging_enabled['TargetPrefix']
27 | end
28 | @logging_enabled = true
29 | end
30 | end
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/multipart.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Multipart < Base
5 | # UUID for the Multipart Upload Event
6 | attr_accessor :upload_id
7 |
8 | # Object name of the Multipart Upload Event
9 | attr_accessor :key
10 |
11 | # Bucket name of the Multipart Upload Event
12 | attr_accessor :bucket
13 |
14 | # Initiation time of the Multipart Upload Event
15 | attr_accessor :initiated
16 |
17 | # reference to client
18 | attr_accessor :client
19 |
20 | def initiated=(initiated)
21 | @initiated = Time.parse(initiated)
22 | end
23 |
24 | # Upload part to Multipart Upload Event
25 | #
26 | # @see Api::BucketMultiparts#bucket_multipart_upload
27 | # @example (see Api::BucketMultiparts#bucket_multipart_upload)
28 | # @raise (see Api::BucketMultiparts#bucket_multipart_upload)
29 | #
30 | # @param number [Integer] the part number, Range in 1~10000.
31 | # @param file [File, bin data] the upload data
32 | #
33 | # @return [HTTParty::Response::Headers]
34 | def upload(*args)
35 | client.bucket_multipart_upload(*args.unshift(upload_id, key)).headers
36 | end
37 |
38 | # Copy exsting object to Multipart Upload Event
39 | #
40 | # @param number [Integer] the part number, Range in 1~10000.
41 | # @param options [Hash] options
42 | #
43 | # @see Api::BucketMultiparts#bucket_multipart_copy_upload
44 | # @example (see Api::BucketMultiparts#bucket_multipart_copy_upload)
45 | # @raise (see Api::BucketMultiparts#bucket_multipart_copy_upload)
46 | #
47 | # @return [true]
48 | def copy(*args)
49 | !!client.bucket_multipart_copy_upload(*args.unshift(upload_id, key))
50 | end
51 |
52 | # List uploaded parts for the Multipart Upload Event
53 | #
54 | # @param options [Hash] options
55 | #
56 | # @see Api::BucketMultiparts#bucket_list_parts
57 | # @example (see Api::BucketMultiparts#bucket_list_parts)
58 | # @raise (see Api::BucketMultiparts#bucket_list_parts)
59 | #
60 | # @return [Array]
61 | def list_parts(options = {})
62 | result = client.bucket_list_parts(upload_id, key, options)
63 | .parsed_response
64 |
65 | parts_keys = %w(ListPartsResult Part)
66 | Utils.wrap(Utils.dig_value(result, *parts_keys)).map do |part|
67 | Struct::Part.new(part)
68 | end
69 | end
70 |
71 | # Complete Multipart Upload Event
72 | #
73 | # @param parts [Array] parts
74 | #
75 | # @see Api::BucketMultiparts#bucket_complete_multipart
76 | # @example (see Api::BucketMultiparts#bucket_complete_multipart)
77 | # @raise (see Api::BucketMultiparts#bucket_complete_multipart)
78 | #
79 | # @return [Struct::Object]
80 | def complete(parts = [])
81 | resp = client.bucket_complete_multipart(upload_id, key, parts)
82 | keys = %w(CompleteMultipartUploadResult)
83 | Struct::Object.new(
84 | Utils.dig_value(resp.parsed_response, *keys).merge(client: client)
85 | )
86 | end
87 |
88 | # Abort Multipart Upload Event
89 | #
90 | # @see Api::BucketMultiparts#bucket_abort_multipart
91 | # @note (see Api::BucketMultiparts#bucket_abort_multipart)
92 | # @example (see Api::BucketMultiparts#bucket_abort_multipart)
93 | # @raise (see Api::BucketMultiparts#bucket_abort_multipart)
94 | #
95 | # @return [true]
96 | def abort
97 | !!client.bucket_abort_multipart(upload_id, key)
98 | end
99 | end
100 | end
101 | end
102 | end
103 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/object.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Object < Base
5 | # Key of object
6 | attr_accessor :key
7 |
8 | # last modified time of object
9 | attr_accessor :last_modified
10 |
11 | # etag of object
12 | attr_accessor :etag
13 | alias_method :e_tag=, :etag=
14 |
15 | # type of object
16 | attr_accessor :type
17 |
18 | # size of object
19 | attr_accessor :size
20 |
21 | # storage class of object
22 | attr_accessor :storage_class
23 |
24 | # owner of object
25 | attr_accessor :owner
26 |
27 | # location of object
28 | attr_accessor :location
29 |
30 | # bucket of object placed
31 | attr_accessor :bucket
32 |
33 | # reference to client
34 | attr_accessor :client
35 |
36 | # Get ACL for object
37 | #
38 | # @raise [RequestError]
39 | #
40 | # @return [String]
41 | def acl!
42 | result = client.bucket_get_object_acl(key).parsed_response
43 | acl_keys = %w(AccessControlPolicy AccessControlList Grant)
44 | Utils.dig_value(result, *acl_keys).strip
45 | end
46 |
47 | # Set ACL for object
48 | #
49 | # @param acl [String] access value, supported value: private, public-read, public-read-write
50 | #
51 | # @raise [RequestError]
52 | #
53 | # @return [true]
54 | def set_acl(acl)
55 | !!client.bucket_set_object_acl(key, acl)
56 | end
57 |
58 | # Get meta information of object
59 | #
60 | # @param headers [Hash] headers
61 | # @option (see #bucket_get_meta_object)
62 | #
63 | # @raise [RequestError]
64 | #
65 | # @return [HTTParty::Response::Headers]
66 | def meta!(*args)
67 | client.bucket_get_meta_object(*args.unshift(key)).headers
68 | end
69 |
70 | class << self
71 | def init_from_response(result, keys, client)
72 | Utils.wrap(Utils.dig_value(result, *keys)).map do |object|
73 | init_from_object(object, client)
74 | end
75 | end
76 |
77 | def init_from_object(object, client)
78 | if object.key?('Key') && object['Key'].end_with?('/')
79 | Struct::Directory.new(object.merge(client: client))
80 | elsif object.key?('Prefix') && object['Prefix'].end_with?('/')
81 | Struct::Directory.new(object.merge(client: client))
82 | else
83 | Struct::File.new(object.merge(client: client))
84 | end
85 | end
86 | end
87 | end
88 | end
89 | end
90 | end
91 |
92 | require 'aliyun/oss/struct/file'
93 | require 'aliyun/oss/struct/directory'
94 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/part.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Part < Base
5 | # [Integer] :number the part number
6 | attr_accessor :number
7 | alias_method :part_number=, :number=
8 |
9 | # [String] :etag the etag for the part
10 | attr_accessor :etag
11 | alias_method :e_tag=, :etag=
12 |
13 | # Last Modified time
14 | attr_accessor :last_modified
15 |
16 | # Part size
17 | attr_accessor :size
18 |
19 | def last_modified=(last_modified)
20 | @last_modified = Time.parse(last_modified)
21 | end
22 |
23 | def to_hash
24 | if valid?
25 | {
26 | 'PartNumber' => number,
27 | 'ETag' => etag
28 | }
29 | else
30 | {}
31 | end
32 | end
33 |
34 | private
35 |
36 | def valid?
37 | number && etag
38 | end
39 | end
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/referer.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Referer < Base
5 | # specify allow empty referer access
6 | attr_accessor :allow_empty
7 |
8 | # specify white list for allows referers
9 | attr_accessor :referers
10 |
11 | def allow_empty=(allow_empty)
12 | @allow_empty = allow_empty == 'true'
13 | end
14 |
15 | def referers=(referers)
16 | @referers = Utils.wrap(referers).map(&:strip)
17 | end
18 | end
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/struct/website.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | module Struct
4 | class Website < Base
5 | # A suffix that is appended to a request that is for a directory on the website endpoint (e.g. if the suffix is index.html and you make a request to samplebucket/images/ the data that is returned will be for the object with the key name images/index.html) The suffix must not be empty and must not include a slash character.
6 | attr_accessor :suffix
7 |
8 | # The object key name to use when a 4XX class error occurs
9 | attr_accessor :error_key
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/utils.rb:
--------------------------------------------------------------------------------
1 | require 'base64'
2 | require 'openssl'
3 | require 'digest'
4 | require 'gyoku'
5 |
6 | module Aliyun
7 | module Oss
8 | class Utils
9 |
10 | # Get endpoint
11 | #
12 | # @example
13 | #
14 | # get_endpoint('bucket-name', 'oss-cn-hangzhou.aliyuncs.com')
15 | # # => 'http://bucket-name.oss-cn-hangzhou.aliyuncs.com'
16 | #
17 | # @param bucket [String] the Bucket name
18 | # @param host [String] the host of Bucket
19 | #
20 | # @return [String]
21 | def self.get_endpoint(bucket, host)
22 | "http://#{bucket}.#{host}/"
23 | end
24 |
25 | # Calculate content length
26 | #
27 | # @return [Integer]
28 | def self.content_size(content)
29 | if content.respond_to?(:size)
30 | content.size
31 | elsif content.is_a?(IO)
32 | content.stat.size
33 | end
34 | end
35 |
36 | # Digest body with MD5 and then encoding with Base64
37 | #
38 | # @return [String]
39 | def self.md5_digest(body)
40 | Base64.encode64(Digest::MD5.digest(body)).strip
41 | end
42 |
43 | # @example
44 | # # { 'a' => 1, 'c' => 3 }
45 | # Utils.hash_slice({ 'a' => 1, 'b' => 2, 'c' => 3 }, 'a', 'c')
46 | #
47 | # @return [Hash]
48 | def self.hash_slice(hash, *selected_keys)
49 | new_hash = {}
50 | selected_keys.each { |k| new_hash[k] = hash[k] if hash.key?(k) }
51 | new_hash
52 | end
53 |
54 | # Convert File or Bin data to bin data
55 | #
56 | # @return [Bin data]
57 | def self.to_data(file_or_bin)
58 | file_or_bin.respond_to?(:read) ? IO.binread(file_or_bin) : file_or_bin
59 | end
60 |
61 | def self.to_xml(hash) # nodoc
62 | %(#{Gyoku.xml(hash)})
63 | end
64 |
65 | # Dig values in deep hash
66 | #
67 | # @example
68 | # dig_value({ 'a' => { 'b' => { 'c' => 3 } } }, 'a', 'b', 'c') # => 3
69 | #
70 | def self.dig_value(hash, *keys)
71 | new_hash = hash.dup
72 |
73 | keys.each do |key|
74 | if new_hash.is_a?(Hash) && new_hash.key?(key)
75 | new_hash = new_hash[key]
76 | else
77 | return nil
78 | end
79 | end
80 | new_hash
81 | end
82 |
83 | # @see {http://apidock.com/rails/String/underscore String#underscore}
84 | def self.underscore(str)
85 | word = str.to_s.dup
86 | word.gsub!(/::/, '/')
87 | word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
88 | word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
89 | word.tr!('-', '_')
90 | word.downcase!
91 | word
92 | end
93 |
94 | # Copy from {https://github.com/rails/rails/blob/14254d82a90b8aa4bd81f7eeebe33885bf83c378/activesupport/lib/active_support/core_ext/array/wrap.rb#L36 ActiveSupport::Array#wrap}
95 | def self.wrap(object)
96 | if object.nil?
97 | []
98 | elsif object.respond_to?(:to_ary)
99 | object.to_ary || [object]
100 | else
101 | [object]
102 | end
103 | end
104 |
105 | def self.stringify_keys!(hash)
106 | hash.keys.each do |key|
107 | hash[key.to_s] = hash.delete(key)
108 | end
109 | end
110 | end
111 | end
112 | end
113 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/version.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | VERSION = '0.1.8'
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/lib/aliyun/oss/xml_generator.rb:
--------------------------------------------------------------------------------
1 | module Aliyun
2 | module Oss
3 | class XmlGenerator
4 | # Generate xml from rules
5 | #
6 | # @example
7 | #
8 | #
9 | #
10 | # RuleID
11 | # Prefix
12 | # Status
13 | #
14 | # Days
15 | #
16 | #
17 | #
18 | def self.generate_lifecycle_rules(rules)
19 | Utils.to_xml(
20 | 'LifecycleConfiguration' => {
21 | 'Rule' => rules.map(&:to_hash)
22 | })
23 | end
24 |
25 | # Generate xml for cors from rules
26 | #
27 | # @example
28 | #
29 | #
30 | #
31 | # the origin you want allow CORS request from
32 | # ...AllowedOrigin>
33 | # HTTP method
34 | # ...AllowedMethod>
35 | # headers that allowed browser to send
36 | # ...AllowedHeader>
37 | # headers in response that can access from client app
38 | # ...ExposeHeader>
39 | # time to cache pre-fight response
40 | #
41 | #
42 | # ...
43 | #
44 | # ...
45 | #
46 | #
47 | def self.generate_cors_rules(rules)
48 | Utils.to_xml(
49 | 'CORSConfiguration' => {
50 | 'CORSRule' => rules.map(&:to_hash)
51 | })
52 | end
53 |
54 | # Generate xml for delete objects
55 | #
56 | # @example
57 | #
58 | #
59 | # true
60 | #
61 | # key
62 | #
63 | # ...
64 | #
65 | #
66 | def self.generate_delete_objects_xml(keys, quiet)
67 | key_objects = keys.map { |key| { 'Key' => key } }
68 | Utils.to_xml(
69 | 'Delete' => {
70 | 'Object' => key_objects,
71 | 'Quiet' => quiet
72 | })
73 | end
74 |
75 | # Generate xml for complete multipart from parts
76 | #
77 | # @example
78 | #
79 | #
80 | # PartNumber
81 | # ETag
82 | #
83 | # ...
84 | #
85 | #
86 | def self.generate_complete_multipart_xml(parts)
87 | Utils.to_xml(
88 | 'CompleteMultipartUpload' => {
89 | 'Part' => parts.map(&:to_hash)
90 | })
91 | end
92 |
93 | # Generate xml for #bucket_create with location
94 | #
95 | # @example
96 | #
97 | #
98 | # BucketRegion
99 | #
100 | #
101 | def self.generate_create_bucket_xml(location)
102 | configuration = {
103 | 'CreateBucketConfiguration' => {
104 | 'LocationConstraint' => location
105 | }
106 | }
107 | Utils.to_xml(configuration)
108 | end
109 |
110 | # Generate xml for enable logging
111 | #
112 | # @example
113 | #
114 | #
115 | #
116 | # TargetBucket
117 | # TargetPrefix
118 | #
119 | #
120 | #
121 | def self.generate_enable_logging_xml(target_bucket, target_prefix)
122 | logging = { 'TargetBucket' => target_bucket }
123 | logging.merge!('TargetPrefix' => target_prefix) if target_prefix
124 | Utils.to_xml(
125 | 'BucketLoggingStatus' => {
126 | 'LoggingEnabled' => logging
127 | })
128 | end
129 |
130 | # Generate xml for enable website
131 | #
132 | # @example
133 | #
134 | #
135 | #
136 | # index.html
137 | #
138 | #
139 | # errorDocument.html
140 | #
141 | #
142 | #
143 | def self.generate_enable_website_xml(suffix, key)
144 | website_configuration = { 'IndexDocument' => { 'Suffix' => suffix } }
145 | website_configuration.merge!('ErrorDocument' => { 'Key' => key }) if key
146 | Utils.to_xml('WebsiteConfiguration' => website_configuration)
147 | end
148 |
149 | # Generate xml for set referer
150 | #
151 | # @example
152 | #
153 | #
154 | # true
155 | #
156 | # http://www.aliyun.com
157 | # https://www.aliyun.com
158 | # http://www.*.com
159 | # https://www.?.aliyuncs.com
160 | # RefererList>
161 | #
162 | #
163 | def self.generate_set_referer_xml(referers, allowed_empty)
164 | Utils.to_xml(
165 | 'RefererConfiguration' => {
166 | 'AllowEmptyReferer' => allowed_empty,
167 | 'RefererList' => {
168 | 'Referer' => referers
169 | }
170 | })
171 | end
172 | end
173 | end
174 | end
175 |
--------------------------------------------------------------------------------
/test/aliyun/authorization_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Authorization do
4 | # Example from https://docs.aliyun.com/#/pub/oss/api-reference/access-control&signature-header#menu4
5 | it 'should get authorization string' do
6 | authorization_value = Aliyun::Oss::Authorization.get_authorization(
7 | '44CF9590006BF252F707',
8 | 'OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV',
9 | verb: 'PUT',
10 | headers: {
11 | 'Content-MD5' => 'ODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=',
12 | 'Content-Type' => 'text/html',
13 | 'x-oss-magic' => 'abracadabra',
14 | 'x-oss-meta-author' => 'foo@bar.com'
15 | },
16 | date: 'Thu, 17 Nov 2005 18:49:58 GMT',
17 | bucket: 'oss-example',
18 | key: 'nelson'
19 | )
20 |
21 | assert_equal('OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=', authorization_value)
22 | end
23 |
24 | it 'should get authorization string when missing headers' do
25 | authorization_value = Aliyun::Oss::Authorization.get_authorization(
26 | '44CF9590006BF252F707',
27 | 'OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV',
28 | verb: 'PUT',
29 | headers: {},
30 | date: 'Thu, 17 Nov 2005 18:49:58 GMT'
31 | )
32 | assert_equal('OSS 44CF9590006BF252F707:PPaaX3Rt4ntpD31O9aqkyCf2pd4=', authorization_value)
33 | end
34 |
35 | it 'should get authorization string when missing x-oss headers' do
36 | authorization_value = Aliyun::Oss::Authorization.get_authorization(
37 | '44CF9590006BF252F707',
38 | 'OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV',
39 | verb: 'PUT',
40 | date: 'Thu, 17 Nov 2005 18:49:58 GMT',
41 | headers: {
42 | 'Content-Type' => 'application/x-www-form-urlencoded'
43 | }
44 | )
45 | assert_equal('OSS 44CF9590006BF252F707:HPW2mvmSOvwZ3J7wuyO751PIUkc=', authorization_value)
46 | end
47 |
48 | # Example from https://docs.aliyun.com/#/pub/oss/api-reference/access-control&signature-url
49 | it 'should get temporary signature' do
50 | temporary_signature = Aliyun::Oss::Authorization.get_temporary_signature(
51 | 'OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV',
52 | 1_141_889_120,
53 | bucket: 'oss-example',
54 | key: 'oss-api.pdf',
55 | verb: 'GET'
56 | )
57 | assert_equal('EwaNTn1erJGkimiJ9WmXgwnANLc%3D', temporary_signature)
58 | end
59 |
60 | # Example from https://docs.aliyun.com/#/pub/oss/api-reference/object&PostObject#menu7
61 | it 'should get base64 policy' do
62 | policy = {
63 | 'expiration' => '2013-12-01T12:00:00Z',
64 | 'conditions' => [
65 | ['content-length-range', 0, 10_485_760],
66 | { 'bucket' => 'ahaha' },
67 | { 'A' => 'a' },
68 | { 'key' => 'ABC' }
69 | ]
70 | }
71 | base64_policy = Aliyun::Oss::Authorization.get_base64_policy(policy)
72 | assert_equal('eyJleHBpcmF0aW9uIjoiMjAxMy0xMi0wMVQxMjowMDowMFoiLCJjb25kaXRpb25zIjpbWyJjb250ZW50LWxlbmd0aC1yYW5nZSIsMCwxMDQ4NTc2MF0seyJidWNrZXQiOiJhaGFoYSJ9LHsiQSI6ImEifSx7ImtleSI6IkFCQyJ9XX0=', base64_policy)
73 | end
74 |
75 | it 'should get policy signature' do
76 | policy = {
77 | 'expiration' => '2013-12-01T12:00:00Z',
78 | 'conditions' => [
79 | ['content-length-range', 0, 10_485_760],
80 | { 'bucket' => 'ahaha' },
81 | { 'A' => 'a' },
82 | { 'key' => 'ABC' }
83 | ]
84 | }
85 | policy_signature = Aliyun::Oss::Authorization.get_policy_signature('OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV', policy)
86 | assert_equal('4tWCtD1uLbM6Uxva3tyNxLoUs2k=', policy_signature)
87 | end
88 | end
89 |
--------------------------------------------------------------------------------
/test/aliyun/client/bucket_multiparts_service_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Client::BucketMultipartsService do
4 | let(:bucket) { 'bucket-name' }
5 | let(:bucket_location) { 'oss-cn-beijing' }
6 | let(:host) { "#{bucket_location}.aliyuncs.com" }
7 | let(:endpoint) { "http://#{bucket_name}.#{host}/" }
8 | let(:access_key) { 'AASSJJKKW94324JJJJ' }
9 | let(:secret_key) { 'OtSSSSxIsf111A7SwPzILwy8Bw21TLhquhboDYROV' }
10 | let(:client) { Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket) }
11 |
12 | let(:object_key) { 'multiparts.data' }
13 |
14 | it '#list should return multiparts' do
15 | path = "http://#{bucket}.#{host}/"
16 | query = { uploads: true }
17 | stub_get_request(path, 'bucket_multiparts/list.xml', query: query)
18 | client.bucket_multiparts.list.each do |obj|
19 | assert_kind_of(Aliyun::Oss::Struct::Multipart, obj)
20 | assert_equal('multipart.data', obj.key)
21 | assert_equal('0004B999EF5A239BB9138C6227D69F95', obj.upload_id)
22 | assert_equal('2012-02-23 04:18:23 UTC', obj.initiated.to_s)
23 | end
24 | end
25 |
26 | it '#init should return multipart' do
27 | path = "http://#{bucket}.#{host}/#{object_key}"
28 | query = { uploads: true }
29 | stub_post_request(path, 'bucket_multiparts/init.xml', query: query)
30 | obj = client.bucket_multiparts.init(object_key)
31 |
32 | assert_kind_of(Aliyun::Oss::Struct::Multipart, obj)
33 | assert_equal(client, obj.client)
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/aliyun/client/bucket_objects_service_test.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require 'test_helper'
3 |
4 | describe Aliyun::Oss::Client::BucketObjectsService do
5 | let(:bucket) { 'bucket-name' }
6 | let(:bucket_location) { 'oss-cn-beijing' }
7 | let(:host) { "#{bucket_location}.aliyuncs.com" }
8 | let(:endpoint) { "http://#{bucket}.#{host}/" }
9 | let(:access_key) { 'AASSJJKKW94324JJJJ' }
10 | let(:secret_key) { 'OtSSSSxIsf111A7SwPzILwy8Bw21TLhquhboDYROV' }
11 | let(:client) { Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket) }
12 |
13 | let(:object_key) { 'object-key' }
14 |
15 | describe '#list' do
16 | it 'should return objects' do
17 | stub_get_request("http://#{bucket}.#{host}/", 'bucket_objects/list.xml')
18 | client.bucket_objects.list.each do |obj|
19 | assert_kind_of(Aliyun::Oss::Struct::File, obj)
20 | end
21 | end
22 |
23 | it 'should return directory' do
24 | stub_get_request("http://#{bucket}.#{host}/", 'bucket_objects/list_dir.xml')
25 | objs = client.bucket_objects.list
26 |
27 | assert_kind_of(Aliyun::Oss::Struct::Directory, objs.last)
28 | assert_equal('fun/movie/', objs.last.key)
29 | end
30 | end
31 |
32 | describe '#create' do
33 | let(:path) { "http://#{bucket}.#{host}/#{object_key}" }
34 |
35 | it 'when 200 response' do
36 | stub_put_request(path, '')
37 | assert client.bucket_objects.create(object_key, 'Hello World!')
38 | end
39 |
40 | it 'when 400 response' do
41 | stub_put_request(path, 'error/400.xml', status: 400)
42 | assert_raises(Aliyun::Oss::RequestError) do
43 | client.bucket_objects.create(object_key, 'Hello World!')
44 | end
45 | end
46 |
47 | it 'should create file with chinese characters key' do
48 | stub_put_request("http://#{bucket}.#{host}/中文文件名.log", '')
49 | assert client.bucket_objects.create('中文文件名.log', 'Hello World!')
50 | end
51 |
52 | it 'should create file with special charaters key' do
53 | stub_put_request("http://#{bucket}.#{host}/special%23中文文件名.log", '')
54 | assert client.bucket_objects.create('special#中文文件名.log', 'Hello World!')
55 |
56 | stub_put_request("http://#{bucket}.#{host}/special%2525中文文件名.log", '')
57 | assert client.bucket_objects.create('special%25中文文件名.log', 'Hello World!')
58 | end
59 | end
60 |
61 | describe '#delete' do
62 | let(:path) { "http://#{bucket}.#{host}/#{object_key}" }
63 |
64 | it 'when 200 response' do
65 | stub_delete_request(path, '')
66 | assert client.bucket_objects.delete(object_key)
67 | end
68 |
69 | it 'when bucket not exist' do
70 | stub_delete_request(path, 'error/404.xml', status: 404)
71 | assert_raises(Aliyun::Oss::RequestError) do
72 | client.bucket_objects.delete(object_key)
73 | end
74 | end
75 | end
76 |
77 | describe '#delete_multiple' do
78 | let(:path) { "http://#{bucket}.#{host}/" }
79 | let(:query) { { delete: true } }
80 |
81 | it 'when 200 response' do
82 | stub_post_request(path, '', query: query)
83 | assert client.bucket_objects.delete_multiple([object_key])
84 | end
85 |
86 | it 'when 400 Response' do
87 | stub_post_request(path, 'error/400.xml', status: 400, query: query)
88 | assert_raises(Aliyun::Oss::RequestError) do
89 | client.bucket_objects.delete_multiple([object_key])
90 | end
91 | end
92 | end
93 |
94 | describe '#copy' do
95 | let(:source_bucket) { 'source-bucket-name' }
96 | let(:source_key) { 'source-key' }
97 | let(:path) { "http://#{bucket}.#{host}/#{object_key}" }
98 |
99 | it 'when 200 response' do
100 | stub_put_request(path, '')
101 | assert client.bucket_objects.copy(object_key, source_bucket, source_key)
102 | end
103 |
104 | it 'when 400 Response' do
105 | stub_put_request(path, 'error/400.xml', status: 400)
106 | assert_raises(Aliyun::Oss::RequestError) do
107 | client.bucket_objects.copy(object_key, source_bucket, source_key)
108 | end
109 | end
110 | end
111 |
112 | it '#get should return string' do
113 | path = "http://#{bucket}.#{host}/#{object_key}"
114 | stub_request(:get, path).to_return(body: 'Hello' * 1000, status: 200)
115 | assert_equal 'Hello' * 1000, client.bucket_objects.get(object_key)
116 | end
117 |
118 | it '#append should return headers' do
119 | path = "http://#{bucket}.#{host}/#{object_key}"
120 | query = { append: true, position: 100 }
121 | headers = { 'x-oss-next-append-position' => 100 }
122 | stub_post_request(path, '', query: query, response_headers: headers)
123 |
124 | result = client.bucket_objects.append(object_key, 'Hello', 100)
125 | assert_kind_of(HTTParty::Response::Headers, result)
126 | assert_equal('100', result['x-oss-next-append-position'])
127 | end
128 | end
129 |
--------------------------------------------------------------------------------
/test/aliyun/client/buckets_service_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Client::BucketsService do
4 | let(:bucket) { 'bucket-name' }
5 | let(:bucket_location) { 'oss-cn-beijing' }
6 | let(:host) { "#{bucket_location}.aliyuncs.com" }
7 | let(:endpoint) { "http://#{bucket}.#{host}/" }
8 | let(:access_key) { 'AASSJJKKW94324JJJJ' }
9 | let(:secret_key) { 'OtSSSSxIsf111A7SwPzILwy8Bw21TLhquhboDYROV' }
10 | let(:client) { Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket) }
11 |
12 | it '#list should return buckets' do
13 | stub_get_request("http://#{host}/", 'buckets/list.xml')
14 | client.buckets.list.each do |obj|
15 | assert_kind_of(Aliyun::Oss::Struct::Bucket, obj)
16 | assert_equal(obj.name, obj.client.bucket)
17 | end
18 | end
19 |
20 | describe '#create' do
21 | let(:bucket_name) { 'valid-bucket-name' }
22 | let(:path) { "http://#{bucket_name}.#{host}/?acl=true" }
23 |
24 | it 'when 200 response' do
25 | stub_put_request(path, '', status: 200)
26 | assert client.buckets.create(bucket_name, 'oss-cn-beijing')
27 | end
28 |
29 | it 'should 400 response' do
30 | stub_put_request(path, 'error/400.xml', status: 400)
31 | assert_raises(Aliyun::Oss::RequestError) do
32 | client.buckets.create(bucket_name, 'oss-cn-beijing')
33 | end
34 | end
35 | end
36 |
37 | describe '#delete' do
38 | let(:bucket_name) { 'valid-bucket-name' }
39 | let(:path) { "http://#{bucket_name}.#{host}/" }
40 |
41 | it 'when 200 response' do
42 | stub_delete_request(path, '')
43 | assert client.buckets.delete(bucket_name)
44 | end
45 |
46 | it 'should bucket not empty' do
47 | stub_delete_request(path, 'error/409.xml', status: 409)
48 | assert_raises(Aliyun::Oss::RequestError) do
49 | client.buckets.delete(bucket_name)
50 | end
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/test/aliyun/struct/bucket_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Struct::Bucket do
4 | let(:bucket_name) { 'bucket-name' }
5 | let(:bucket_location) { 'oss-cn-beijing' }
6 | let(:host) { "#{bucket_location}.aliyuncs.com" }
7 | let(:endpoint) { "http://#{bucket_name}.#{host}/" }
8 | let(:access_key) { 'AASSJJKKW94324JJJJ' }
9 | let(:secret_key) { 'OtSSSSxIsf111A7SwPzILwy8Bw21TLhquhboDYROV' }
10 | let(:client) do
11 | Aliyun::Oss::Client.new(
12 | access_key,
13 | secret_key,
14 | host: host,
15 | bucket: bucket_name
16 | )
17 | end
18 | let(:bucket) do
19 | Aliyun::Oss::Struct::Bucket.new(
20 | name: bucket_name,
21 | location: location,
22 | client: client
23 | )
24 | end
25 |
26 | it '#location! should get via HTTP' do
27 | stub_get_request(endpoint, 'bucket/location.xml', query: { location: true })
28 | assert_equal('oss-cn-hangzhou', bucket.location!)
29 | end
30 |
31 | describe '#logging!' do
32 | it 'should get via HTTP' do
33 | stub_get_request(endpoint, 'bucket/logging.xml', query: { logging: true })
34 | logging = bucket.logging!
35 |
36 | assert_kind_of(Aliyun::Oss::Struct::Logging, logging)
37 | assert_equal(true, logging.logging_enabled)
38 | assert_equal('mybucketlogs', logging.target_bucket)
39 | assert_equal('mybucket-access_log/', logging.target_prefix)
40 | end
41 |
42 | it 'when not set logging' do
43 | stub_get_request(endpoint, 'bucket/no_logging.xml', query: { logging: true })
44 | logging = bucket.logging!
45 |
46 | assert_kind_of(Aliyun::Oss::Struct::Logging, logging)
47 | assert_equal(false, logging.logging_enabled)
48 | end
49 | end
50 |
51 | it '#acl! should get via HTTP' do
52 | stub_get_request(endpoint + '?acl=true', 'bucket/acl.xml')
53 | assert_equal('private', bucket.acl!)
54 | end
55 |
56 | it '#website! should get via HTTP' do
57 | stub_get_request(endpoint + '?website=true', 'bucket/website.xml')
58 | obj = bucket.website!
59 |
60 | assert_kind_of(Aliyun::Oss::Struct::Website, obj)
61 | assert_equal('index.html', obj.suffix)
62 | assert_equal('error.html', obj.error_key)
63 | end
64 |
65 | describe '#referer!' do
66 | it 'should get via HTTP' do
67 | stub_get_request(endpoint + '?referer=true', 'bucket/referer.xml')
68 | obj = bucket.referer!
69 |
70 | assert_kind_of(Aliyun::Oss::Struct::Referer, obj)
71 | assert_equal(false, obj.allow_empty)
72 | assert_equal([
73 | 'http://www.aliyun.com',
74 | 'https://www.aliyun.com',
75 | 'http://www.*.com',
76 | 'https://www.?.aliyuncs.com'
77 | ], obj.referers)
78 | end
79 |
80 | it 'when not set referer' do
81 | stub_get_request(endpoint + '?referer=true', 'bucket/no_referer.xml')
82 | obj = bucket.referer!
83 |
84 | assert_kind_of(Aliyun::Oss::Struct::Referer, obj)
85 | assert_equal(true, obj.allow_empty)
86 | end
87 | end
88 |
89 | describe '#lifecycle!' do
90 | it 'for days lifecycle' do
91 | stub_get_request(endpoint + '?lifecycle=true', 'bucket/days_lifecycle.xml')
92 | bucket.lifecycle!.each do |obj|
93 | assert_kind_of(Aliyun::Oss::Struct::LifeCycle, obj)
94 | assert_equal('delete after one day', obj.id)
95 | assert_equal('logs/', obj.prefix)
96 | assert_equal(true, obj.enabled)
97 | assert_equal(1, obj.days)
98 | end
99 | end
100 |
101 | it 'for date lifecycle' do
102 | stub_get_request(endpoint + '?lifecycle=true', 'bucket/date_lifecycle.xml')
103 | bucket.lifecycle!.each do |obj|
104 | assert_kind_of(Aliyun::Oss::Struct::LifeCycle, obj)
105 | assert_equal('delete at date', obj.id)
106 | assert_equal('logs/', obj.prefix)
107 | assert_equal(true, obj.enabled)
108 | assert_equal('2022-10-11 00:00:00 UTC', obj.date.to_s)
109 | end
110 | end
111 |
112 | it 'when not set lifecycle' do
113 | path = endpoint + '?lifecycle=true'
114 | stub_get_request(path, 'bucket/no_lifecycle.xml', status: 404)
115 | assert_raises(Aliyun::Oss::RequestError) do
116 | bucket.lifecycle!
117 | end
118 | end
119 | end
120 |
121 | it '#cors! should get via HTTP' do
122 | stub_get_request(endpoint + '?cors=true', 'bucket/cors.xml')
123 |
124 | bucket.cors!.each do |obj|
125 | assert_kind_of(Aliyun::Oss::Struct::Cors, obj)
126 | assert_equal(['*'], obj.allowed_origin)
127 | assert_equal(['GET'], obj.allowed_method)
128 | assert_equal(['*'], obj.allowed_header)
129 | assert_equal(['x-oss-test'], obj.expose_header)
130 | assert_equal('100', obj.max_age_seconds)
131 | end
132 | end
133 |
134 | it '#enable_lifecycle should invoke #bucket_enable_lifecycle & return true' do
135 | stub_put_request(endpoint + '?lifecycle=true', '')
136 | rule = Aliyun::Oss::Struct::LifeCycle.new(
137 | prefix: 'oss-sdk',
138 | enabled: false,
139 | date: Time.now
140 | )
141 | assert bucket.enable_lifecycle([rule])
142 | end
143 |
144 | it '#enable_cors should invoke #bucket_enable_cors & return true' do
145 | stub_put_request(endpoint + '?cors=true', '')
146 | rule = Aliyun::Oss::Struct::Cors.new(
147 | allowed_method: ['get'],
148 | allowed_origin: ['*']
149 | )
150 | assert bucket.enable_cors([rule])
151 | end
152 |
153 | it '#enable_logging should invoke #bucket_enable_logging & return true' do
154 | stub_put_request(endpoint + '?logging=true', '')
155 | assert bucket.enable_logging('oss-sdk-dev-beijing')
156 | end
157 |
158 | it '#enable_website should invoke #bucket_enable_website & return true' do
159 | stub_put_request(endpoint + '?website=true', '')
160 | assert bucket.enable_website('index.html')
161 | end
162 |
163 | %w(website lifecycle cors logging).each do |prop|
164 | it "#disable_#{prop} should invoke #bucket_disable_#{prop} & return true" do
165 | stub_delete_request(endpoint + "?#{prop}=false", '')
166 | assert bucket.send("disable_#{prop}".to_sym)
167 | end
168 | end
169 |
170 | it '#set_referer should invoke #bucket_set_referer & return true' do
171 | stub_put_request(endpoint + '?referer=true', '')
172 | assert bucket.set_referer(['http://aliyun.com'], true)
173 | end
174 |
175 | it '#set_acl should invoke #bucket_set_acl & return true' do
176 | stub_put_request(endpoint + '?acl=true', '')
177 | assert bucket.set_acl('private')
178 | end
179 |
180 | it '#preflight! should return true' do
181 | stub_options_request(endpoint + 'index.html', '')
182 | assert bucket.preflight('index.html', '*', 'GET')
183 | assert bucket.options('index.html', '*', 'GET')
184 | end
185 | end
186 |
--------------------------------------------------------------------------------
/test/aliyun/struct/directory_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Struct::Directory do
4 | let(:bucket_name) { 'bucket-name' }
5 | let(:bucket_location) { 'oss-cn-beijing' }
6 | let(:host) { "#{bucket_location}.aliyuncs.com" }
7 | let(:endpoint) { "http://#{bucket_name}.#{host}/" }
8 | let(:access_key) { 'AASSJJKKW94324JJJJ' }
9 | let(:secret_key) { 'OtSSSSxIsf111A7SwPzILwy8Bw21TLhquhboDYROV' }
10 | let(:client) do
11 | Aliyun::Oss::Client.new(
12 | access_key,
13 | secret_key,
14 | host: host,
15 | bucket: bucket_name
16 | )
17 | end
18 |
19 | it '#list should list objects under directory' do
20 | path = "http://#{bucket_name}.#{host}/?prefix=fun/movie/"
21 | stub_get_request(path, 'directory/list.xml')
22 | dir = Aliyun::Oss::Struct::Directory.new(key: 'fun/movie/', client: client)
23 | dir.list.each do |obj|
24 | assert_kind_of(Aliyun::Oss::Struct::File, obj)
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/aliyun/struct/file_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Struct::File do
4 | let(:bucket_name) { 'bucket-name' }
5 | let(:bucket_location) { 'oss-cn-beijing' }
6 | let(:host) { "#{bucket_location}.aliyuncs.com" }
7 | let(:endpoint) { "http://#{bucket_name}.#{host}/" }
8 | let(:access_key) { 'AASSJJKKW94324JJJJ' }
9 | let(:secret_key) { 'OtSSSSxIsf111A7SwPzILwy8Bw21TLhquhboDYROV' }
10 | let(:client) do
11 | Aliyun::Oss::Client.new(
12 | access_key,
13 | secret_key,
14 | host: host,
15 | bucket: bucket_name
16 | )
17 | end
18 |
19 | let(:object_key) { 'object-key' }
20 | let(:struct_object) do
21 | Aliyun::Oss::Struct::File.new(
22 | key: object_key,
23 | client: client
24 | )
25 | end
26 |
27 | it '#share_link should get share link' do
28 | Timecop.freeze(Time.parse('2015-11-04 21:59:00 +0000')) do
29 | expected = 'http://bucket-name.oss-cn-beijing.aliyuncs.com/object-key?' \
30 | "OSSAccessKeyId=#{access_key}&Expires=1446677940&Signature=4vOq8%2BTnk2ZVBOWYtwu%2FiYEnUaM%3D"
31 | assert_equal(expected, struct_object.share_link(3600))
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/test/aliyun/struct/multipart_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Struct::Multipart do
4 | let(:bucket_name) { 'bucket-name' }
5 | let(:bucket_location) { 'oss-cn-beijing' }
6 | let(:host) { "#{bucket_location}.aliyuncs.com" }
7 | let(:endpoint) { "http://#{bucket_name}.#{host}/" }
8 | let(:access_key) { 'AASSJJKKW94324JJJJ' }
9 | let(:secret_key) { 'OtSSSSxIsf111A7SwPzILwy8Bw21TLhquhboDYROV' }
10 | let(:client) do
11 | Aliyun::Oss::Client.new(
12 | access_key,
13 | secret_key,
14 | host: host,
15 | bucket: bucket_name
16 | )
17 | end
18 |
19 | let(:upload_id) { 'DFGHJRGHJTRHYJCVBNMCVBNGHJ' }
20 | let(:object_key) { 'multipart.data' }
21 | let(:multipart) do
22 | Aliyun::Oss::Struct::Multipart.new(
23 | upload_id: upload_id,
24 | key: object_key,
25 | client: client
26 | )
27 | end
28 |
29 | it '#upload should return headers' do
30 | path = endpoint + 'multipart.data'
31 | query = { 'partNumber' => 1, 'uploadId' => upload_id }
32 | headers = { 'ETag' => 'HFGHJRTYHJVBNMFGHJFGHJ' }
33 | stub_put_request(path, '', query: query, response_headers: headers)
34 |
35 | result = multipart.upload(1, 'hello')
36 | assert_kind_of(HTTParty::Response::Headers, result)
37 | assert_equal('HFGHJRTYHJVBNMFGHJFGHJ', result['ETag'])
38 | end
39 |
40 | it '#copy should return true' do
41 | path = endpoint + object_key
42 | query = { 'partNumber' => 1, 'uploadId' => upload_id }
43 | stub_put_request(path, '', query: query)
44 |
45 | options = {
46 | source_bucket: 'source-bucket-name',
47 | source_key: 'source-key',
48 | range: 'bytes=1-100'
49 | }
50 |
51 | assert multipart.copy(1, options)
52 | end
53 |
54 | it '#list_parts should return parts' do
55 | path = endpoint + object_key
56 | query = { 'uploadId' => upload_id }
57 | stub_get_request(path, 'multipart/list_parts.xml', query: query)
58 |
59 | multipart.list_parts.each do |part|
60 | assert_kind_of(Aliyun::Oss::Struct::Part, part)
61 | assert_equal('5', part.number)
62 | assert_equal('"7265F4D211B56873A381D321F586E4A9"', part.etag)
63 | assert_equal('2012-02-23 07:02:03 UTC', part.last_modified.to_s)
64 | assert_equal('1024', part.size)
65 | end
66 | end
67 |
68 | it '#complete should return the complete object' do
69 | part1 = Aliyun::Oss::Struct::Part.new(
70 | number: 1, etag: 'EDB4BC6E69180BC4759633E7B0EED0E0'
71 | )
72 | part2 = Aliyun::Oss::Struct::Part.new(
73 | number: 2, etag: 'EDB4BC6E69180BC4759633E7B0ESJKHW'
74 | )
75 |
76 | path = endpoint + object_key
77 | query = { 'uploadId' => upload_id }
78 | stub_post_request(path, 'multipart/complete.xml', query: query)
79 |
80 | obj = multipart.complete([part1, part2])
81 |
82 | assert_kind_of(Aliyun::Oss::Struct::Object, obj)
83 | assert_equal(path, obj.location)
84 | assert_equal(bucket_name, obj.bucket)
85 | assert_equal(object_key, obj.key)
86 | end
87 |
88 | it '#abort should return true' do
89 | path = endpoint + object_key
90 | query = { 'uploadId' => upload_id }
91 | stub_delete_request(path, '', query: query)
92 |
93 | assert multipart.abort
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/test/aliyun/struct/object_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Struct::Object do
4 | let(:bucket_name) { 'bucket-name' }
5 | let(:bucket_location) { 'oss-cn-beijing' }
6 | let(:host) { "#{bucket_location}.aliyuncs.com" }
7 | let(:endpoint) { "http://#{bucket_name}.#{host}/" }
8 | let(:access_key) { 'AASSJJKKW94324JJJJ' }
9 | let(:secret_key) { 'OtSSSSxIsf111A7SwPzILwy8Bw21TLhquhboDYROV' }
10 | let(:client) do
11 | Aliyun::Oss::Client.new(
12 | access_key,
13 | secret_key,
14 | host: host,
15 | bucket: bucket_name
16 | )
17 | end
18 |
19 | let(:object_key) { 'object-key' }
20 | let(:struct_object) do
21 | Aliyun::Oss::Struct::Object.new(
22 | key: object_key,
23 | client: client
24 | )
25 | end
26 |
27 | it '#acl! should get via HTTP & return string' do
28 | path = endpoint + object_key + '?acl=true'
29 | stub_get_request(path, 'object/acl.xml')
30 | assert_equal('public-read', struct_object.acl!)
31 | end
32 |
33 | it '#set_acl! should result true' do
34 | path = endpoint + object_key + '?acl=true'
35 | stub_put_request(path, '')
36 | assert struct_object.set_acl('private')
37 | end
38 |
39 | it '#meta should return hash contains headers' do
40 | path = endpoint + object_key
41 | response_headers = { 'x-oss-meta-location' => 'hangzhou' }
42 | stub_head_request(path, '', response_headers: response_headers)
43 |
44 | headers = struct_object.meta!
45 | assert_equal('hangzhou', headers['x-oss-meta-location'])
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/test/aliyun/utils_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | describe Aliyun::Oss::Utils do
4 | it 'should convert hash to xml' do
5 | expected_xml = "" \
6 | '2 1 3 '
7 | original_hash = { 'a' => { 'e' => 2, 'd' => 1 }, 'c' => 3 }
8 | assert_equal expected_xml, Aliyun::Oss::Utils.to_xml(original_hash)
9 | end
10 |
11 | it 'should dig value from deep hash' do
12 | hash = { 'a' => { 'b' => { 'c' => 3 } } }
13 | assert_equal(3, Aliyun::Oss::Utils.dig_value(hash, 'a', 'b', 'c'))
14 | assert_equal({ 'c' => 3 }, Aliyun::Oss::Utils.dig_value(hash, 'a', 'b'))
15 | assert_equal(nil, Aliyun::Oss::Utils.dig_value(hash, 'a', 'b', 'c', 'd'))
16 | end
17 |
18 | it 'stringify_keys should convert hash keys to string' do
19 | a_hash = { a: 1, b: 2, c: 3 }
20 | expected_hash = { 'a' => 1, 'b' => 2, 'c' => 3 }
21 | Aliyun::Oss::Utils.stringify_keys!(a_hash)
22 | assert_equal expected_hash, a_hash
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 00220120222
5 | user_example
6 |
7 |
8 | private
9 |
10 |
11 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/cors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | *
5 | GET
6 | *
7 | x-oss-test
8 | 100
9 |
10 |
11 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/date_lifecycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | delete at date
5 | logs/
6 | Enabled
7 |
8 | 2022-10-11T00:00:00.000Z
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/days_lifecycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | delete after one day
5 | logs/
6 | Enabled
7 |
8 | 1
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/location.xml:
--------------------------------------------------------------------------------
1 |
2 | oss-cn-hangzhou
3 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/logging.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mybucketlogs
5 | mybucket-access_log/
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/no_lifecycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | oss-example
4 | NoSuchLifecycle
5 | No Row found in Lifecycle Table.
6 | 534B372974E88A4D89060099
7 | oss-example.oss.aliyuncs.com
8 |
9 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/no_logging.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/no_referer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/referer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
5 | http://www.aliyun.com
6 | https://www.aliyun.com
7 | http://www.*.com
8 | https://www.?.aliyuncs.com
9 |
10 |
11 |
--------------------------------------------------------------------------------
/test/fixtures/bucket/website.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | index.html
5 |
6 |
7 | error.html
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/fixtures/bucket_multiparts/init.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | multipart_upload
4 | multipart.data
5 | 0004B9894A22E5B1888A1E29F8236E2D
6 |
7 |
--------------------------------------------------------------------------------
/test/fixtures/bucket_multiparts/list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | oss-example
4 |
5 |
6 | oss.avi
7 | 0004B99B8E707874FC2D692FA5D77D3F
8 |
9 |
10 | 1000
11 | false
12 |
13 | multipart.data
14 | 0004B999EF5A239BB9138C6227D69F95
15 | 2012-02-23T04:18:23.000Z
16 |
17 |
18 |
--------------------------------------------------------------------------------
/test/fixtures/bucket_objects/list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | oss-example
4 | fun
5 |
6 | 100
7 |
8 | false
9 |
10 | fun/movie/001.avi
11 | 2012-02-24T08:43:07.000Z
12 | "5B3C1A2E053D763E1B002CC607C5A0FE"
13 | Normal
14 | 344606
15 | Standard
16 |
17 | 00220120222
18 | user_example
19 |
20 |
21 |
22 | fun/movie/007.avi
23 | 2012-02-24T08:43:27.000Z
24 | "5B3C1A2E053D763E1B002CC607C5A0FE"
25 | Normal
26 | 344606
27 | Standard
28 |
29 | 00220120222
30 | user_example
31 |
32 |
33 |
34 | fun/test.jpg
35 | 2012-02-24T08:42:32.000Z
36 | "5B3C1A2E053D763E1B002CC607C5A0FE"
37 | Normal
38 | 344606
39 | Standard
40 |
41 | 00220120222
42 | user_example
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/test/fixtures/bucket_objects/list_dir.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | oss-example
4 | fun/
5 |
6 | 100
7 | /
8 | false
9 |
10 | fun/test.jpg
11 | 2012-02-24T08:42:32.000Z
12 | "5B3C1A2E053D763E1B002CC607C5A0FE"
13 | Normal
14 | 344606
15 | Standard
16 |
17 | 00220120222
18 | user_example
19 |
20 |
21 |
22 | fun/movie/
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/fixtures/buckets/list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ut_test_put_bucket
5 | ut_test_put_bucket
6 |
7 |
8 |
9 | oss-cn-hangzhou-a
10 | xz02tphky6fjfiuc0
11 | 2014-05-15T11:18:32.000Z
12 |
13 |
14 | oss-cn-hangzhou-a
15 | xz02tphky6fjfiuc1
16 | 2014-05-15T11:18:32.000Z
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/test/fixtures/directory/list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | oss-example
4 | fun
5 |
6 | 100
7 |
8 | false
9 |
10 | fun/movie/001.avi
11 | 2012-02-24T08:43:07.000Z
12 | "5B3C1A2E053D763E1B002CC607C5A0FE"
13 | Normal
14 | 344606
15 | Standard
16 |
17 | 00220120222
18 | user_example
19 |
20 |
21 |
22 | fun/movie/007.avi
23 | 2012-02-24T08:43:27.000Z
24 | "5B3C1A2E053D763E1B002CC607C5A0FE"
25 | Normal
26 | 344606
27 | Standard
28 |
29 | 00220120222
30 | user_example
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/test/fixtures/error/400.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | InvalidArgument
5 |
6 |
7 | Invalid Argument
8 |
9 |
10 | 4e63c87a-71dc-87f7-11b5-583a600e0038
11 |
12 |
13 | oss-cn-hangzhou.aliyuncs.com
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test/fixtures/error/404.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NotFound
5 |
6 |
7 | Not Found
8 |
9 |
10 | 4e63c87a-71dc-87f7-11b5-583a600e0038
11 |
12 |
13 | oss-cn-hangzhou.aliyuncs.com
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test/fixtures/error/409.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | BucketNotEmpty
5 |
6 |
7 | Bucket Not Empty
8 |
9 |
10 | 4e63c87a-71dc-87f7-11b5-583a600e0038
11 |
12 |
13 | oss-cn-hangzhou.aliyuncs.com
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test/fixtures/multipart/complete.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | http://bucket-name.oss-cn-beijing.aliyuncs.com/multipart.data
4 | bucket-name
5 | multipart.data
6 | B864DB6A936D376F9F8D3ED3BBE540DD-3
7 |
8 |
--------------------------------------------------------------------------------
/test/fixtures/multipart/list_parts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | multipart_upload
4 | multipart.data
5 | 0004B999EF5A239BB9138C6227D69F95
6 | 5
7 | 1000
8 | false
9 |
10 | 5
11 | 2012-02-23T07:02:03.000Z
12 | "7265F4D211B56873A381D321F586E4A9"
13 | 1024
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test/fixtures/object/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 00220120222
5 | 00220120222
6 |
7 |
8 | public-read
9 |
10 |
11 |
--------------------------------------------------------------------------------
/test/fixtures/sample.txt:
--------------------------------------------------------------------------------
1 | Hello Aliyun!
2 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2 | if ENV['TESTLOCAL']
3 | require 'simplecov'
4 | SimpleCov.start
5 | else
6 | require 'coveralls'
7 | Coveralls.wear!
8 | end
9 |
10 | require 'aliyun/oss'
11 |
12 | require 'minitest/autorun'
13 | require 'mocha/mini_test'
14 | require 'webmock/minitest'
15 | require 'timecop'
16 |
17 | def stub_get_request(path, file_path, options = {})
18 | stub_client_request(:get, path, file_path, options)
19 | end
20 |
21 | def stub_put_request(path, file_path, options = {})
22 | stub_client_request(:put, path, file_path, options)
23 | end
24 |
25 | def stub_post_request(path, file_path, options = {})
26 | stub_client_request(:post, path, file_path, options)
27 | end
28 |
29 | def stub_delete_request(path, file_path, options = {})
30 | stub_client_request(:delete, path, file_path, options)
31 | end
32 |
33 | def stub_options_request(path, file_path, options = {})
34 | stub_client_request(:options, path, file_path, options)
35 | end
36 |
37 | def stub_head_request(path, file_path, options = {})
38 | stub_client_request(:head, path, file_path, options)
39 | end
40 |
41 | def stub_client_request(verb, path, file_path, options = {})
42 | body = file_path.empty? ? file_path : File.new(fixture_path(file_path))
43 | headers = options.fetch(:response_headers, {})
44 | .merge(content_type: 'application/xml')
45 |
46 | stub_request(verb, path)
47 | .with(query: options.fetch(:query, {}))
48 | .to_return(
49 | status: options[:status] || 200,
50 | headers: headers,
51 | body: body
52 | )
53 | end
54 |
55 | def fixture_path(path)
56 | File.join(File.dirname(__FILE__), 'fixtures', path)
57 | end
58 |
--------------------------------------------------------------------------------
/todo.md:
--------------------------------------------------------------------------------
1 | ## TODO
2 |
3 | + Command Line Tool
4 | + Custom Domain Support
5 | + Get Download URL
6 | + Multipart#upload return headers
7 |
--------------------------------------------------------------------------------
/wiki/bucket.md:
--------------------------------------------------------------------------------
1 | ## Bucket
2 |
3 | Bucket is a namespace in OSS, as well as management entity for high functions such as pricing, access control, logging; Bucket names are global uniqueness throughout the OSS services, and cannot be modified. Each Object stored in the OSS must contained in a Bucket. An application, such as the picture sharing website, can correspond to one or more Bucket. A user can create up to 10 Bucket, but each bucket can store unlimit objects, there is no limit to the number of storage capacity each buckte highest support 2 PB.
4 |
5 | ### Name Spec
6 |
7 | + Only contains lowercase letters, Numbers, dash (-)
8 | + Must begin with lowercase letters or Numbers
9 | + Length must be between 3-63 bytes
10 |
11 |
12 | ### Create Bucket
13 |
14 | require 'aliyun/oss'
15 |
16 | access_key, secret_key = "your id", "your secret"
17 | host = "oss-cn-hangzhou.aliyuncs.com"
18 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
19 |
20 | # create a private bucket on oss-cn-beijing
21 | res = client.bucket_create('new-bucket', 'oss-cn-beijing', 'private')
22 | puts res.success?, res.headers
23 |
24 | You can specify bucket name, location(default 'oss-cn-hangzhou') and acl(default: 'private') when create new bucket.
25 |
26 |
27 | ### List all buckets
28 |
29 | To get all buckets use Client#list_buckets:
30 |
31 |
32 | require 'aliyun/oss'
33 |
34 | access_key, secret_key = "your id", "your secret"
35 | host = "oss-cn-hangzhou.aliyuncs.com"
36 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
37 |
38 | res = client.list_buckets
39 | puts res.success?, res.parsed_response
40 |
41 |
42 | ### Set ACL
43 |
44 | With Client#bucket_set_acl you can modify the ACL:
45 |
46 | require 'aliyun/oss'
47 |
48 | access_key, secret_key = "your id", "your secret"
49 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
50 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
51 |
52 | # supported value: public-read-write | public-read | private
53 | res = client.bucket_set_acl("public-read")
54 | puts res.success?, res.parsed_response
55 |
56 | Now, it support public-read-write | public-read | private, more detail visit: [Bucket ACL](https://docs.aliyun.com/#/pub/oss/product-documentation/acl&bucket-acl)
57 |
58 |
59 | ### Get ACL
60 |
61 | To get current ACL of Bucket, use Client#bucket_get_acl:
62 |
63 | require 'aliyun/oss'
64 |
65 | access_key, secret_key = "your id", "your secret"
66 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
67 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
68 |
69 | res = client.bucket_get_acl
70 | puts res.success?, res.parsed_response
71 |
72 |
73 | ### Get Bucket Location
74 |
75 | Get bucket's data center location, use Client#bucket_get_location:
76 |
77 | require 'aliyun/oss'
78 |
79 | access_key, secret_key = "your id", "your secret"
80 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
81 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
82 |
83 | res = client.bucket_get_location
84 | puts res.success?, res.parsed_response
85 |
86 | To get more bucket information, visit Client#bucket_get_xxx methods [here](http://www.rubydoc.info/gems/aliyun-oss-sdk/Aliyun/Oss/Client).
87 |
88 |
89 | ### Delete Bucket
90 |
91 | If you do need one bucket, delete it with Client#bucket_delete:
92 |
93 | require 'aliyun/oss'
94 |
95 | access_key, secret_key = "your id", "your secret"
96 | host = "oss-cn-hangzhou.aliyuncs.com"
97 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
98 |
99 | res = client.bucket_delete("deleted-bucket-name")
100 | puts res.success?, res.headers
101 |
102 | Note: when the bucket is not empty(existing object or [Multipart Uploaded](./multipart.md) parts), the delete will fail.
103 |
104 |
105 | OK, Let's visit [Objects](./object.md)
106 |
--------------------------------------------------------------------------------
/wiki/cors.md:
--------------------------------------------------------------------------------
1 | ## CORS
2 |
3 | CORS allow web application visit resources not belongs it's domain. OSS provide interface to help developer control the premissions.
4 |
5 |
6 | ### Set CORS
7 |
8 |
9 | With Client#bucket_enable_cors, you can set cors easily:
10 |
11 | require 'aliyun/oss'
12 |
13 | access_key, secret_key = "your id", "your secret"
14 | host = "oss-cn-hangzhou.aliyuncs.com"
15 | bucket = "bucket-name"
16 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
17 |
18 | rule = Aliyun::Oss::Struct::Cors.new(allowed_methods: ['get'], allowed_origins: ['*'])
19 | res = client.bucket_enable_cors([rule])
20 | puts res.success?, res.headers
21 |
22 | More about the rules, visit [OSS API](https://docs.aliyun.com/#/pub/oss/api-reference/cors&PutBucketcors) and [Struct::Cors]()
23 |
24 |
25 | ### Get CORS Rules
26 |
27 | To get current cors rules, you can use Client#bucket_get_cors:
28 |
29 |
30 | require 'aliyun/oss'
31 |
32 | access_key, secret_key = "your id", "your secret"
33 | host = "oss-cn-hangzhou.aliyuncs.com"
34 | bucket = "bucket-name"
35 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
36 |
37 | res = client.bucket_get_cors
38 | puts res.success?, res.parsed_response
39 |
40 |
41 | ### Disable CORS
42 |
43 | If you want to diable CORS, just like below:
44 |
45 | require 'aliyun/oss'
46 |
47 | access_key, secret_key = "your id", "your secret"
48 | host = "oss-cn-hangzhou.aliyuncs.com"
49 | bucket = "bucket-name"
50 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
51 |
52 | # create a private bucket on oss-cn-beijing
53 | res = client.bucket_disable_cors
54 | puts res.success?, res.headers
55 |
56 | Note: disable CORS will remove all existing CORS Rules.
57 |
58 |
59 | Now, Let's go to next section: [LifeCycle](./lifecycle.md)
60 |
--------------------------------------------------------------------------------
/wiki/error.md:
--------------------------------------------------------------------------------
1 | ## Error
2 |
3 | ### Handle Error
4 |
5 | If a error occurs when visit the OSS, the OSS will be return a error code and error message, making it easy for users to locate problems, and make the appropriate treatment. For code not 2XX, you can get information:
6 |
7 | require 'aliyun/oss'
8 |
9 | client = Aliyun::Oss::Client.new('ACCESS_KEY', 'SECRET_KEY', host: 'oss-cn-hangzhou.aliyuncs.com', bucket: 'oss-sdk-dev-hangzhou')
10 |
11 | res = client.bucket_create("invalid_bucket_name")
12 | unless res.success?
13 | puts "Code: #{res.code}"
14 | puts "Message: #{res.message}"
15 | puts "Request id: #{res.parsed_response['Error']['RequestId']}"
16 | end
17 |
18 | Here,
19 |
20 | + Code: the error code
21 | + Message: the error message
22 | + requestId: It's the UUID to uniquely identifies this request; When you can't solve the problem, can the RequestId to request help from the OSS development engineer.
23 |
24 |
25 | # Error Code
26 |
27 | | code | summary | HTTP Status|
28 | |---|---|---|
29 | |AccessDenied |Access denied | 403|
30 | |BucketAlreadyExists | Bucket Already Exist| 409|
31 | |BucketNotEmpty |Bucket Not Empty| 409|
32 | |EntityTooLarge | Entry Too Large| 400|
33 | |EntityTooSmall | Entry Too Small| 400|
34 | |FileGroupTooLarge |File Group Too Large| 400|
35 | |InvalidLinkName | Object Link Same With Object| 400|
36 | |LinkPartNotExist | Object Not Exist| 400|
37 | |ObjectLinkTooLarge | Object Too Much | 400|
38 | |FieldItemTooLong | Field Too Large| 400|
39 | |FilePartInterity | File Part Already Changed| 400|
40 | |FilePartNotExist |File Part Not Exist| 400|
41 | |FilePartStale | File Part Expired| 400|
42 | |IncorrectNumberOfFilesInPOSTRequest| File Count Invalid| 400|
43 | |InvalidArgument |Invalid Argument| 400|
44 | |InvalidAccessKeyId | Access Key ID Not Exist| 403|
45 | |InvalidBucketName | The specified bucket is not valid.| 400|
46 | |InvalidDigest | Invalid Digest | 400|
47 | |InvalidEncryptionAlgorithmError | Specified Encoding-Type Error | 400|
48 | |InvalidObjectName |Invalid Object Name| 400
49 | |InvalidPart | Invalid Part| 400|
50 | |InvalidPartOrder |Invalid Part Order| 400|
51 | |InvalidPolicyDocument | Invalid Policy| 400|
52 | |InvalidTargetBucketForLogging |Invalid Target Bucket For Logging| 400|
53 | |InternalError |Internal Error| 500|
54 | |MalformedXML | XML Invalid| 400|
55 | |MalformedPOSTRequest | Requested XML Invalid | 400|
56 | |MaxPOSTPreDataLengthExceededError | Body except file Too Large | 400|
57 | |MethodNotAllowed |Method Not Allowed| 405|
58 | |MissingArgument |Missing Argument| 411|
59 | |MissingContentLength |Missing Content Length| 411|
60 | |NoSuchBucket |No Such Bucket| 404|
61 | |NoSuchKey |No Such Key| 404|
62 | |NoSuchUpload |Multipart Upload ID Not Exist| 404|
63 | |NotImplemented |Not Implemented| 501|
64 | |PreconditionFailed |Precondition Failed| 412|
65 | |RequestTimeTooSkewed |Request Time Large Than 15 minutes| 403|
66 | |RequestTimeout |Request Timeout| 400|
67 | |RequestIsNotMultiPartContent | Content-Type Invalid| 400|
68 | |SignatureDoesNotMatch |Signature Does Not Match|403|
69 | |TooManyBuckets |Too Many Buckets| 400|
70 |
--------------------------------------------------------------------------------
/wiki/get_start.md:
--------------------------------------------------------------------------------
1 | ## Getting started
2 |
3 | Here, you can know how to do some basic operation with Aliyun OSS SDK.
4 |
5 |
6 | ### Step-1. Init a client
7 |
8 | Mostly OSS API are handled by [Aliyun::Oss::Client](http://www.rubydoc.info/gems/aliyun-oss-sdk/Aliyun/Oss/Client) class, Let's create a instance first:
9 |
10 | require 'aliyun/oss'
11 |
12 | access_key, secret_key = "your id", "your secret"
13 | host = "oss-cn-hangzhou.aliyuncs.com"
14 | bucket = "bucket-name"
15 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
16 |
17 | Here, access_key/secret_key is is your access credentials, Aliyun provide three ways to get access credentials, get more information [here](https://docs.aliyun.com/#/pub/oss/product-documentation/acl&RESTAuthentication).
18 |
19 |
20 | ### Step-2. Create Bucket
21 |
22 | Buckets are global object in OSS, so find a uniqueness name for your bucket, Or it fail when create. It can used to store objects. Now, we create a bucket:
23 |
24 | require 'aliyun/oss'
25 |
26 | access_key, secret_key = "your id", "your secret"
27 | host = "oss-cn-hangzhou.aliyuncs.com"
28 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
29 |
30 | # create a private bucket on oss-cn-beijing
31 | res = client.bucket_create('new-bucket', 'oss-cn-beijing', 'private')
32 | puts res.success?, res.headers
33 |
34 | In our library, most instance methods of Client return [HttpartyResponse](http://www.rubydoc.info/github/jnunemaker/httparty/HTTParty/Response), you can use rich methods to fetch your interesting message.
35 |
36 |
37 | ### Step-3 Upload Object
38 |
39 | Object is the most basic unit of data in OSS, you can simple imagine it's just a file. here, we upload a object to OSS:
40 |
41 | require 'aliyun/oss'
42 |
43 | access_key, secret_key = "your id", "your secret"
44 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
45 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
46 |
47 | file = File.new("path/to/test.txt")
48 | res = client.bucket_create_object("test.txt", file)
49 | puts res.success?, res.headers
50 |
51 |
52 | ### Step-4 list all object
53 |
54 | After you complete some upload, maybe you want to list the objects in the bucket:
55 |
56 |
57 | require 'aliyun/oss'
58 |
59 | access_key, secret_key = "your id", "your secret"
60 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
61 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
62 |
63 | res = client.bucket_list_objects()
64 | puts res.success?, res.parsed_response
65 |
66 | With correct parameters, you can get more flexible result. you can get detailed Paramters [here](http://www.rubydoc.info/gems/aliyun-oss-sdk/Aliyun%2FOss%2FClient%3Abucket_list_objects).
67 |
68 |
69 | ### Step-5. Get special object
70 |
71 | Now, you want to get a special object:
72 |
73 | require 'aliyun/oss'
74 |
75 | access_key, secret_key = "your id", "your secret"
76 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
77 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
78 |
79 | res = client.bucket_get_object("test.txt")
80 | puts res.success?, res.headers
81 | # save the response to your local file system
82 | File.open("file.png", "wb") { |f| f << res.parsed_response }
83 |
84 | Next, Visit more about [Bucket](./bucket.md)
--------------------------------------------------------------------------------
/wiki/installation.md:
--------------------------------------------------------------------------------
1 | ## Installation
2 |
3 | It's a Ruby Gem, so you can install it like any Gem:
4 |
5 | $ gem install aliyun-oss-sdk
6 |
7 | If you use Gemfile manage your Gems, Add below to your Gemfile.
8 |
9 | gem "aliyun-oss-sdk"
10 |
11 | And run:
12 |
13 | $ bundle install
14 |
15 | Now, [Getting started](./get_start.md)
--------------------------------------------------------------------------------
/wiki/lifecycle.md:
--------------------------------------------------------------------------------
1 | ## LifeCycle
2 |
3 | OSS provide LifeCycle to help user manage lifecycle of object. User can create LifeCycle rules to manage objects. At present, user can create rule to auto delete Objects. Each rule is composed by following several parts:
4 |
5 | + Prefix of Object name, only match the prefix will apply this rule.
6 | + Operation, user want to take for the matched objects.
7 | + Date or Days, which user can specify expired date or days to expire.
8 |
9 |
10 | ### Set LifeCycle
11 |
12 |
13 | In the LifeCycle, you can contains 1000 rules at max.
14 |
15 | Each rule contains:
16 |
17 | + ID: each rule ID must keep uniqueness and cannot contain others(eg: abc and abcd).
18 | + Prefix: it can used to apply rule for object with the prefix
19 | + Status: defined the status for the rule, Only support Enabled and Disabled.
20 | + Expiration: Date or Days, used to specify expired date or specify expired after x days from last modified date.
21 |
22 | In our Library, to use Struct::LifeCycle to define a rule:
23 |
24 | # Define a rule to auto delete objects with prefix: logs-prod- after 7 days since last modified date
25 | rule1 = Aliyun::Oss::Struct::LifeCycle.new({ prefix: 'logs-prod-', days: 7, enable: true })
26 |
27 | # Defome a ri;e tp auto delete objects with prefix: logs-dev- at Time.now + 24*60*60
28 | rule2 = Aliyun::Oss::Struct::LifeCycle.new({ prefix: 'logs-dev', date: Time.now + 24*60*60, enable: true })
29 |
30 |
31 | To set your LifeCycle with this rules:
32 |
33 | require 'aliyun/oss'
34 |
35 | access_key, secret_key = "your id", "your secret"
36 | host = "oss-cn-hangzhou.aliyuncs.com"
37 | bucket = "bucket-name"
38 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
39 |
40 | res = client.bucket_enable_lifecycle([rule1, rule2]) puts res.success?, res.headers
41 |
42 | ### Get LifeCycle
43 |
44 | To get LifeCycle for bucket, use Client#bucket_get_lifecycle:
45 |
46 | require 'aliyun/oss'
47 |
48 | access_key, secret_key = "your id", "your secret"
49 | host = "oss-cn-hangzhou.aliyuncs.com"
50 | bucket = "bucket-name"
51 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
52 |
53 | res = client.bucket_get_lifecycle
54 | puts res.success?, res.parsed_response
55 |
56 |
57 | ### Disable LifeCycle
58 |
59 |
60 | With Client#bucket_disable_lifecycle, you can disable LifeCycle:
61 |
62 |
63 | require 'aliyun/oss'
64 |
65 | access_key, secret_key = "your id", "your secret"
66 | host = "oss-cn-hangzhou.aliyuncs.com"
67 | bucket = "bucket-name"
68 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
69 |
70 | res = client.bucket_disable_lifecycle
71 | puts res.success?, res.headers
72 |
73 |
74 | Next, Let's discuss about [Error](./error.md)
75 |
76 |
--------------------------------------------------------------------------------
/wiki/multipart.md:
--------------------------------------------------------------------------------
1 | ## Multipart Upload
2 |
3 | Besides simple upload via put, OSS provide another way to upload large file -- Multipart Upload, Here we list some normal application scenarios:
4 |
5 | + To support breakpoint upload
6 | + Upload file large than 100 MB
7 | + Network is bad, and the connection between the OSS server often disconnected
8 | + Upload a file before, unable to determine the size of the uploaded files
9 |
10 |
11 | Now, Let's start party!
12 |
13 |
14 | ### Initialize
15 |
16 | Before start a Multipart Upload, we need first initialize a event:
17 |
18 |
19 | require 'aliyun/oss'
20 |
21 | access_key, secret_key = "your id", "your secret"
22 | host = "oss-cn-hangzhou.aliyuncs.com"
23 | bucket = "bucket-name"
24 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
25 |
26 | # Step-1 Init a Multipart Upload
27 | res = client.bucket_init_multipart("Exciting-Ruby.mp4", { 'Content-Type' => 'video/mp4' })
28 | if res.success?
29 | puts "Upload ID: #{res.parsed_response['InitiateMultipartUploadResult']['UploadId']}"
30 | else
31 | puts res.code, res.message
32 | end
33 |
34 | Upload ID is the UUID for the Multipart Upload Event, store it for use later.
35 |
36 | ### Upload Part from local
37 |
38 | require 'aliyun/oss'
39 |
40 | access_key, secret_key = "your id", "your secret"
41 | host = "oss-cn-hangzhou.aliyuncs.com"
42 | bucket = "bucket-name"
43 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
44 |
45 | res = client.bucket_multipart_upload("Upload ID", "Exciting-Ruby.mp4", 1, file_or_bin)
46 |
47 | if res.success?
48 | puts "etag: #{res.headers['etag']}"
49 | else
50 | puts res.code, res.message
51 | end
52 |
53 | Store the etag, it will used for complete a Multipart Upload.
54 |
55 | It can used to upload part to a object. Please note:
56 |
57 | + Multipart Upload requirements every parts greater than 100 KB except last one
58 | + In order to ensure that data safe when network transmission, strongly recommend to include meta: content-md5, after receiving the data, OSS using the md5 value to prove the validity of the upload data, if they are inconsistent returns InvalidDigest.
59 | + The Part number range is 1~10000. If beyond this range, the OSS will return InvalidArgument.
60 | + If you upload from the same file, be careful for the upload position
61 |
62 | ### Complete Multipart Upload
63 |
64 | require 'aliyun/oss'
65 |
66 | access_key, secret_key = "your id", "your secret"
67 | host = "oss-cn-hangzhou.aliyuncs.com"
68 | bucket = "bucket-name"
69 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
70 |
71 | part1 = Aliyun::Oss::Struct::Part.new({ number: 1, etag: 'etag1' })
72 | part2 = Aliyun::Oss::Struct::Part.new({ number: 2, etag: 'etag2' })
73 | part3 = Aliyun::Oss::Struct::Part.new({ number: 3, etag: 'etag3' })
74 | res = client.bucket_complete_multipart("Upload ID", "Exciting-Ruby.mp4", [part1, part2, part3])
75 |
76 |
77 | Here, we create Aliyun::Oss::Struct::Part to build your part, use Part#valid? to valid the object.
78 |
79 | ### Abort Multipart Upload
80 |
81 | If some Problem occurs, you may want to abort a Multipart Upload:
82 |
83 | require 'aliyun/oss'
84 |
85 | access_key, secret_key = "your id", "your secret"
86 | host = "oss-cn-hangzhou.aliyuncs.com"
87 | bucket = "bucket-name"
88 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
89 |
90 | res = client.bucket_abort_multipart("Upload ID", "Exciting-Ruby.mp4")
91 |
92 | After abort a multipart, all uploaded parts will be destroyed, But Note: If some others are upload parts to this object when your abort, they may be missing, so invoke a few times if you have access in concurrent.
93 |
94 | ### List Multipart Upload
95 |
96 | To get all Multipart Upload in this Bucket:
97 |
98 | require 'aliyun/oss'
99 |
100 | access_key, secret_key = "your id", "your secret"
101 | host = "oss-cn-hangzhou.aliyuncs.com"
102 | bucket = "bucket-name"
103 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
104 |
105 | res = client.bucket_list_multiparts
106 | puts res.success?, res.parsed_response
107 |
108 | Same with all other list method, it support prefix, delimiter, marker to get flexible results.
109 |
110 |
111 | ### List Uploaded Parts
112 |
113 | Sometimes, you want to know which parts are uploaded.
114 |
115 | require 'aliyun/oss'
116 |
117 | access_key, secret_key = "your id", "your secret"
118 | host = "oss-cn-hangzhou.aliyuncs.com"
119 | bucket = "bucket-name"
120 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
121 |
122 | res = client.bucket_list_parts("Upload ID")
123 | puts res.success?, res.parsed_response
124 |
125 |
126 | OK, It's time to visit [CORS](./cors.md)
127 |
128 |
--------------------------------------------------------------------------------
/wiki/object_based/bucket.md:
--------------------------------------------------------------------------------
1 | ## Bucket
2 |
3 | Bucket is a namespace in OSS, as well as management entity for high functions such as pricing, access control, logging; Bucket names are global uniqueness throughout the OSS services, and cannot be modified. Each Object stored in the OSS must contained in a Bucket. An application, such as the picture sharing website, can correspond to one or more Bucket. A user can create up to 10 Bucket, but each bucket can store unlimit objects, there is no limit to the number of storage capacity each buckte highest support 2 PB.
4 |
5 | ### Name Spec
6 |
7 | + Only contains lowercase letters, Numbers, dash (-)
8 | + Must begin with lowercase letters or Numbers
9 | + Length must be between 3-63 bytes
10 |
11 |
12 | ### Create Bucket
13 |
14 | require 'aliyun/oss'
15 |
16 | access_key, secret_key = "your id", "your secret"
17 | host = "oss-cn-hangzhou.aliyuncs.com"
18 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
19 |
20 | # create a private bucket on oss-cn-beijing
21 | begin
22 | client.buckets.create('new-bucket', 'oss-cn-beijing', 'private')
23 | rescue Aliyun::Oss::RequestError => e
24 | puts "Bucket create fail", e.code, e.message, e.request_id
25 | end
26 |
27 | You can specify bucket name, location(default 'oss-cn-hangzhou') and acl(default: 'private') when create new bucket.
28 |
29 |
30 | ### List all buckets
31 |
32 | To get all buckets use Client#list_buckets:
33 |
34 |
35 | require 'aliyun/oss'
36 |
37 | access_key, secret_key = "your id", "your secret"
38 | host = "oss-cn-hangzhou.aliyuncs.com"
39 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
40 |
41 | begin
42 | buckets = client.buckets.list
43 | rescue Aliyun::Oss::RequestError => e
44 | puts "List Buckets fail", e.code, e.message, e.request_id
45 | end
46 |
47 | ### Set ACL
48 |
49 | With Client#bucket_set_acl you can modify the ACL:
50 |
51 | require 'aliyun/oss'
52 |
53 | access_key, secret_key = "your id", "your secret"
54 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
55 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
56 |
57 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
58 | # supported value: public-read-write | public-read | private
59 | begin
60 | bucket.set_acl('public-read')
61 | rescue Aliyun::Oss::RequestError => e
62 | puts "Set ACL fail", e.code, e.message, e.request_id
63 | end
64 |
65 | Now, it support public-read-write | public-read | private, more detail visit: [Bucket ACL](https://docs.aliyun.com/#/pub/oss/product-documentation/acl&bucket-acl)
66 |
67 |
68 | ### Get ACL
69 |
70 | To get current ACL of Bucket, use Client#bucket_get_acl:
71 |
72 | require 'aliyun/oss'
73 |
74 | access_key, secret_key = "your id", "your secret"
75 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
76 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
77 |
78 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
79 | begin
80 | acl = bucket.acl!
81 | rescue Aliyun::Oss::RequestError => e
82 | puts "Get ACL fail", e.code, e.message, e.request_id
83 | end
84 |
85 | ### Get Bucket Location
86 |
87 | Get bucket's data center location, use Client#bucket_get_location:
88 |
89 | require 'aliyun/oss'
90 |
91 | access_key, secret_key = "your id", "your secret"
92 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
93 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
94 |
95 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
96 | begin
97 | location = bucket.location!
98 | rescue Aliyun::Oss::RequestError => e
99 | puts "Get Location fail", e.code, e.message, e.request_id
100 | end
101 |
102 | To get more bucket information, visit Bucket#xxx! methods [here](http://www.rubydoc.info/gems/aliyun-oss-sdk/0.1.1/Aliyun/Oss/Struct/Bucket).
103 |
104 |
105 | ### Delete Bucket
106 |
107 | If you do need one bucket, delete it with Client#bucket_delete:
108 |
109 | require 'aliyun/oss'
110 |
111 | access_key, secret_key = "your id", "your secret"
112 | host = "oss-cn-hangzhou.aliyuncs.com"
113 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
114 |
115 | begin
116 | client.buckets.delete("deleted-bucket-name")
117 | rescue Aliyun::Oss::RequestError => e
118 | puts "Delete Bucket fail", e.code, e.message, e.request_id
119 | end
120 |
121 | Note: when the bucket is not empty(existing object or [Multipart Uploaded](./multipart.md) parts), the delete will fail.
122 |
123 |
124 | OK, Let's visit [Objects](./object.md)
125 |
--------------------------------------------------------------------------------
/wiki/object_based/cors.md:
--------------------------------------------------------------------------------
1 | ## CORS
2 |
3 | CORS allow web application visit resources not belongs it's domain. OSS provide interface to help developer control the premissions.
4 |
5 |
6 | ### Set CORS
7 |
8 |
9 | With Bucket#enable_cors, you can set cors easily:
10 |
11 | require 'aliyun/oss'
12 |
13 | access_key, secret_key = "your id", "your secret"
14 | host = "oss-cn-hangzhou.aliyuncs.com"
15 | bucket = "bucket-name"
16 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
17 |
18 | begin
19 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
20 | rule = Aliyun::Oss::Struct::Cors.new(allowed_methods: ['get'], allowed_origins: ['*'])
21 | bucket.enable_cors([rule])
22 | rescue Aliyun::Oss::RequestError => e
23 | puts "Set CORS fail", e.code, e.message, e.request_id
24 | end
25 |
26 | More about the rules, visit [OSS API](https://docs.aliyun.com/#/pub/oss/api-reference/cors&PutBucketcors) and [Struct::Cors](http://www.rubydoc.info/gems/aliyun-oss-sdk/0.1.1/Aliyun/Oss/Struct/Cors)
27 |
28 |
29 | ### Get CORS Rules
30 |
31 | To get current cors rules, you can use Client#bucket_get_cors:
32 |
33 |
34 | require 'aliyun/oss'
35 |
36 | access_key, secret_key = "your id", "your secret"
37 | host = "oss-cn-hangzhou.aliyuncs.com"
38 | bucket = "bucket-name"
39 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
40 |
41 | begin
42 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
43 | cors = bucket.cors!
44 | rescue Aliyun::Oss::RequestError => e
45 | puts "Get CORS fail", e.code, e.message, e.request_id
46 | end
47 |
48 |
49 | ### Disable CORS
50 |
51 | If you want to diable CORS, just like below:
52 |
53 | require 'aliyun/oss'
54 |
55 | access_key, secret_key = "your id", "your secret"
56 | host = "oss-cn-hangzhou.aliyuncs.com"
57 | bucket = "bucket-name"
58 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
59 |
60 | # create a private bucket on oss-cn-beijing
61 | begin
62 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
63 | bucket.disable_cors
64 | rescue Aliyun::Oss::RequestError => e
65 | puts "Disable CORS fail", e.code, e.message, e.request_id
66 | end
67 |
68 | Note: disable CORS will remove all existing CORS Rules.
69 |
70 |
71 | Now, Let's go to next section: [LifeCycle](./lifecycle.md)
72 |
--------------------------------------------------------------------------------
/wiki/object_based/error.md:
--------------------------------------------------------------------------------
1 | ## Error
2 |
3 | ### Handle Error
4 |
5 | If a error occurs when visit the OSS, the OSS will be return a error code and error message, making it easy for users to locate problems, and make the appropriate treatment. For code not 2XX, you can get information:
6 |
7 | require 'aliyun/oss'
8 |
9 | client = Aliyun::Oss::Client.new('ACCESS_KEY', 'SECRET_KEY', host: 'oss-cn-hangzhou.aliyuncs.com', bucket: 'oss-sdk-dev-hangzhou')
10 |
11 | begin
12 | client.buckets.create("invalid_bucket_name")
13 | rescue Aliyun::Oss::RequestError => e
14 | puts "Code: #{e.code}"
15 | puts "Message: #{e.message}"
16 | puts "Request id: #{e.request_id}"
17 | end
18 |
19 | Here,
20 |
21 | + Code: the error code
22 | + Message: the error message
23 | + requestId: It's the UUID to uniquely identifies this request; When you can't solve the problem, can the RequestId to request help from the OSS development engineer.
24 |
25 |
26 | # Error Code
27 |
28 | | code | summary | HTTP Status|
29 | |---|---|
30 | |AccessDenied |Access denied | 403|
31 | |BucketAlreadyExists | Bucket Already Exist| 409|
32 | |BucketNotEmpty |Bucket Not Empty| 409|
33 | |EntityTooLarge | Entry Too Large| 400|
34 | |EntityTooSmall | Entry Too Small| 400|
35 | |FileGroupTooLarge |File Group Too Large| 400|
36 | |InvalidLinkName | Object Link Same With Object| 400|
37 | |LinkPartNotExist | Object Not Exist| 400|
38 | |ObjectLinkTooLarge | Object Too Much | 400|
39 | |FieldItemTooLong | Field Too Large| 400|
40 | |FilePartInterity | File Part Already Changed| 400|
41 | |FilePartNotExist |File Part Not Exist| 400|
42 | |FilePartStale | File Part Expired| 400|
43 | |IncorrectNumberOfFilesInPOSTRequest| File Count Invalid| 400|
44 | |InvalidArgument |Invalid Argument| 400|
45 | |InvalidAccessKeyId | Access Key ID Not Exist| 403|
46 | |InvalidBucketName | The specified bucket is not valid.| 400|
47 | |InvalidDigest | Invalid Digest | 400|
48 | |InvalidEncryptionAlgorithmError | Specified Encoding-Type Error | 400|
49 | |InvalidObjectName |Invalid Object Name| 400
50 | |InvalidPart | Invalid Part| 400|
51 | |InvalidPartOrder |Invalid Part Order| 400|
52 | |InvalidPolicyDocument | Invalid Policy| 400|
53 | |InvalidTargetBucketForLogging |Invalid Target Bucket For Logging| 400|
54 | |InternalError |Internal Error| 500|
55 | |MalformedXML | XML Invalid| 400|
56 | |MalformedPOSTRequest | Requested XML Invalid | 400|
57 | |MaxPOSTPreDataLengthExceededError | Body except file Too Large | 400|
58 | |MethodNotAllowed |Method Not Allowed| 405|
59 | |MissingArgument |Missing Argument| 411|
60 | |MissingContentLength |Missing Content Length| 411|
61 | |NoSuchBucket |No Such Bucket| 404|
62 | |NoSuchKey |No Such Key| 404|
63 | |NoSuchUpload |Multipart Upload ID Not Exist| 404|
64 | |NotImplemented |Not Implemented| 501|
65 | |PreconditionFailed |Precondition Failed| 412|
66 | |RequestTimeTooSkewed |Request Time Large Than 15 minutes| 403|
67 | |RequestTimeout |Request Timeout| 400|
68 | |RequestIsNotMultiPartContent | Content-Type Invalid| 400|
69 | |SignatureDoesNotMatch |Signature Does Not Match|403|
70 | |TooManyBuckets |Too Many Buckets| 400|
71 |
--------------------------------------------------------------------------------
/wiki/object_based/get_start.md:
--------------------------------------------------------------------------------
1 | ## Getting started
2 |
3 | Here, you can know how to do some basic operation with Aliyun OSS SDK.
4 |
5 |
6 | ### Step-1. Init a client
7 |
8 | Mostly OSS API are handled by [Aliyun::Oss::Client](http://www.rubydoc.info/gems/aliyun-oss-sdk/Aliyun/Oss/Client) class, Let's create a instance first:
9 |
10 | require 'aliyun/oss'
11 |
12 | access_key, secret_key = "your id", "your secret"
13 | host = "oss-cn-hangzhou.aliyuncs.com"
14 | bucket = "bucket-name"
15 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
16 |
17 | Here, access_key/secret_key is is your access credentials, Aliyun provide three ways to get access credentials, get more information [here](https://docs.aliyun.com/#/pub/oss/product-documentation/acl&RESTAuthentication).
18 |
19 |
20 | ### Step-2. Create Bucket
21 |
22 | Buckets are global object in OSS, so find a uniqueness name for your bucket, Or it fail when create. It can used to store objects. Now, we create a bucket:
23 |
24 | require 'aliyun/oss'
25 |
26 | access_key, secret_key = "your id", "your secret"
27 | host = "oss-cn-hangzhou.aliyuncs.com"
28 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
29 |
30 | # create a private bucket on oss-cn-beijing
31 | begin
32 | client.buckets.create('new-bucket', 'oss-cn-beijing', 'private')
33 | rescue Aliyun::Oss::RequestError => e
34 | puts "Bucket create fail", e.code, e.message, e.request_id
35 | end
36 |
37 |
38 | ### Step-3 Upload Object
39 |
40 | Object is the most basic unit of data in OSS, you can simple imagine it's just a file. here, we upload a object to OSS:
41 |
42 | require 'aliyun/oss'
43 |
44 | access_key, secret_key = "your id", "your secret"
45 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
46 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
47 |
48 | file = File.new("path/to/test.txt")
49 | begin
50 | client.bucket_objects.create("test.txt", file)
51 | rescue Aliyun::Oss::RequestError => e
52 | puts "Upload Object fail", e.code, e.message, e.request_id
53 | end
54 |
55 | ### Step-4 list all object
56 |
57 | After you complete some upload, maybe you want to list the objects in the bucket:
58 |
59 |
60 | require 'aliyun/oss'
61 |
62 | access_key, secret_key = "your id", "your secret"
63 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
64 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
65 |
66 | begin
67 | objects = client.bucket_objects.list
68 | rescue Aliyun::Oss::RequestError => e
69 | puts "Cannot list objects", e.code, e.message, e.request_id
70 | end
71 |
72 | With correct parameters, you can get more flexible result. you can get detailed Paramters [here](http://www.rubydoc.info/gems/aliyun-oss-sdk/Aliyun%2FOss%2FClient%3Abucket_list_objects).
73 |
74 |
75 | ### Step-5. Get special object
76 |
77 | Now, you want to get a special object:
78 |
79 | require 'aliyun/oss'
80 |
81 | access_key, secret_key = "your id", "your secret"
82 | host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
83 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
84 |
85 | begin
86 | body = client.bucket_objects.get("test.txt")
87 | # save the response to your local file system
88 | File.open("test.txt", "wb") { |f| f << body.read }
89 | rescue Aliyun::Oss::RequestError => e
90 | puts "Get object fail", e.code, e.message, e.request_id
91 | end
92 |
93 | Next, Visit more about [Bucket](./bucket.md)
--------------------------------------------------------------------------------
/wiki/object_based/installation.md:
--------------------------------------------------------------------------------
1 | ## Installation
2 |
3 | It's a Ruby Gem, so you can install it like any Gem:
4 |
5 | $ gem install aliyun-oss-sdk
6 |
7 | If you use Gemfile manage your Gems, Add below to your Gemfile.
8 |
9 | gem "aliyun-oss-sdk"
10 |
11 | And run:
12 |
13 | $ bundle install
14 |
15 | Now, [Getting started](./get_start.md)
--------------------------------------------------------------------------------
/wiki/object_based/lifecycle.md:
--------------------------------------------------------------------------------
1 | ## LifeCycle
2 |
3 | OSS provide LifeCycle to help user manage lifecycle of object. User can create LifeCycle rules to manage objects. At present, user can create rule to auto delete Objects. Each rule is composed by following several parts:
4 |
5 | + Prefix of Object name, only match the prefix will apply this rule.
6 | + Operation, user want to take for the matched objects.
7 | + Date or Days, which user can specify expired date or days to expire.
8 |
9 |
10 | ### Set LifeCycle
11 |
12 |
13 | In the LifeCycle, you can contains 1000 rules at max.
14 |
15 | Each rule contains:
16 |
17 | + ID: each rule ID must keep uniqueness and cannot contain others(eg: abc and abcd).
18 | + Prefix: it can used to apply rule for object with the prefix
19 | + Status: defined the status for the rule, Only support Enabled and Disabled.
20 | + Expiration: Date or Days, used to specify expired date or specify expired after x days from last modified date.
21 |
22 | In our Library, to use Struct::LifeCycle to define a rule:
23 |
24 | # Define a rule to auto delete objects with prefix: logs-prod- after 7 days since last modified date
25 | rule1 = Aliyun::Oss::Struct::LifeCycle.new({ prefix: 'logs-prod-', days: 7, enable: true })
26 |
27 | # Define a rule to auto delete objects with prefix: logs-dev- at Time.now + 24*60*60
28 | rule2 = Aliyun::Oss::Struct::LifeCycle.new({ prefix: 'logs-dev', date: Time.now + 24*60*60, enable: true })
29 |
30 |
31 | To set your LifeCycle with this rules:
32 |
33 | require 'aliyun/oss'
34 |
35 | access_key, secret_key = "your id", "your secret"
36 | host = "oss-cn-hangzhou.aliyuncs.com"
37 | bucket = "bucket-name"
38 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
39 |
40 | begin
41 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
42 | bucket.enable_lifecycle([rule1, rule2])
43 | rescue Aliyun::Oss::RequestError => e
44 | puts "Enable Lifecycle fail", e.code, e.message, e.request_id
45 | end
46 |
47 | ### Get LifeCycle
48 |
49 | To get LifeCycle for bucket, use Client#bucket_get_lifecycle:
50 |
51 | require 'aliyun/oss'
52 |
53 | access_key, secret_key = "your id", "your secret"
54 | host = "oss-cn-hangzhou.aliyuncs.com"
55 | bucket = "bucket-name"
56 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
57 |
58 | begin
59 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
60 | bucket.lifecycle!
61 | rescue Aliyun::Oss::RequestError => e
62 | puts "Enable Lifecycle fail", e.code, e.message, e.request_id
63 | end
64 |
65 |
66 | ### Disable LifeCycle
67 |
68 |
69 | With Client#bucket_disable_lifecycle, you can disable LifeCycle:
70 |
71 |
72 | require 'aliyun/oss'
73 |
74 | access_key, secret_key = "your id", "your secret"
75 | host = "oss-cn-hangzhou.aliyuncs.com"
76 | bucket = "bucket-name"
77 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
78 |
79 | begin
80 | bucket = Aliyun::Oss::Struct::Bucket.new(client: client)
81 | bucket.disable_lifecycle
82 | rescue Aliyun::Oss::RequestError => e
83 | puts "Disable Lifecycle fail", e.code, e.message, e.request_id
84 | end
85 |
86 |
87 | Next, Let's discuss about [Error](./error.md)
88 |
89 |
--------------------------------------------------------------------------------
/wiki/object_based/multipart.md:
--------------------------------------------------------------------------------
1 | ## Multipart Upload
2 |
3 | Besides simple upload via put, OSS provide another way to upload large file -- Multipart Upload, Here we list some normal application scenarios:
4 |
5 | + To support breakpoint upload
6 | + Upload file large than 100 MB
7 | + Network is bad, and the connection between the OSS server often disconnected
8 | + Upload a file before, unable to determine the size of the uploaded files
9 |
10 |
11 | Now, Let's start party!
12 |
13 |
14 | ### Initialize
15 |
16 | Before start a Multipart Upload, we need first initialize a event:
17 |
18 |
19 | require 'aliyun/oss'
20 |
21 | access_key, secret_key = "your id", "your secret"
22 | host = "oss-cn-hangzhou.aliyuncs.com"
23 | bucket = "bucket-name"
24 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
25 |
26 | begin
27 | # Step-1 Init a Multipart Upload
28 | multipart = client.bucket_multiparts.init("Exciting-Ruby.mp4", { 'Content-Type' => 'video/mp4' })
29 | puts "Upload ID: #{multipart.upload_id}"
30 | rescue Aliyun::Oss::RequestError => e
31 | puts "Init Multipart fail", e.code, e.message, e.request_id
32 | end
33 |
34 | Upload ID is the UUID for the Multipart Upload Event, store it for use later.
35 |
36 | ### Upload Part from local
37 |
38 | require 'aliyun/oss'
39 |
40 | access_key, secret_key = "your id", "your secret"
41 | host = "oss-cn-hangzhou.aliyuncs.com"
42 | bucket = "bucket-name"
43 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
44 |
45 | begin
46 | multipart = client.bucket_multiparts.init("Exciting-Ruby.mp4", { 'Content-Type' => 'video/mp4' })
47 | headers = multipart.upload("Exciting-Ruby.mp4", 1, file_or_bin)
48 | puts "etag: #{headers['etag']}"
49 | rescue Aliyun::Oss::RequestError => e
50 | puts "Upload to Multipart fail", e.code, e.message, e.request_id
51 | end
52 |
53 | Store the etag, it will used for complete a Multipart Upload.
54 |
55 | It can used to upload part to a object. Please note:
56 |
57 | + Multipart Upload requirements every parts greater than 100 KB except last
58 | + In order to ensure that data safe when network transmission, strongly recommend to include meta: content-md5, after receiving the data, OSS using the md5 value to prove the validity of the upload data, if they are inconsistent returns InvalidDigest.
59 | + The Part number range is 1~10000. If beyond this range, the OSS will return InvalidArgument.
60 | + If you upload from the same file, be careful for the upload position
61 |
62 | ### Complete Multipart Upload
63 |
64 | require 'aliyun/oss'
65 |
66 | access_key, secret_key = "your id", "your secret"
67 | host = "oss-cn-hangzhou.aliyuncs.com"
68 | bucket = "bucket-name"
69 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
70 |
71 | part1 = Aliyun::Oss::Struct::Part.new({ number: 1, etag: 'etag1' })
72 | part2 = Aliyun::Oss::Struct::Part.new({ number: 2, etag: 'etag2' })
73 | part3 = Aliyun::Oss::Struct::Part.new({ number: 3, etag: 'etag3' })
74 | begin
75 | multipart.complete([part1, part2, part3])
76 | rescue Aliyun::Oss::RequestError => e
77 | puts "Complete Multipart fail", e.code, e.message, e.request_id
78 | end
79 |
80 |
81 | Here, we create Aliyun::Oss::Struct::Part to build your part, use Part#valid? to valid the object.
82 |
83 | ### Abort Multipart Upload
84 |
85 | If some Problem occurs, you may want to abort a Multipart Upload:
86 |
87 | require 'aliyun/oss'
88 |
89 | access_key, secret_key = "your id", "your secret"
90 | host = "oss-cn-hangzhou.aliyuncs.com"
91 | bucket = "bucket-name"
92 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
93 |
94 | begin
95 | multipart.abort
96 | rescue Aliyun::Oss::RequestError => e
97 | puts "Upload to Multipart fail", e.code, e.message, e.request_id
98 | end
99 |
100 | After abort a multipart, all uploaded parts will be destroyed, But Note: If some others are upload parts to this object when your abort, they may be missing, so invoke a few times if you have access in concurrent.
101 |
102 | ### List Multipart Upload
103 |
104 | To get all Multipart Upload in this Bucket:
105 |
106 | require 'aliyun/oss'
107 |
108 | access_key, secret_key = "your id", "your secret"
109 | host = "oss-cn-hangzhou.aliyuncs.com"
110 | bucket = "bucket-name"
111 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
112 |
113 | multiparts = client.bucket_multiparts.list
114 |
115 | Same with all other list method, it support prefix, delimiter, marker to get flexible results.
116 |
117 |
118 | ### List Uploaded Parts
119 |
120 | Sometimes, you want to know which parts are uploaded.
121 |
122 | require 'aliyun/oss'
123 |
124 | access_key, secret_key = "your id", "your secret"
125 | host = "oss-cn-hangzhou.aliyuncs.com"
126 | bucket = "bucket-name"
127 | client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
128 |
129 | parts = multipart.list_parts
130 |
131 |
132 | OK, It's time to visit [CORS](./cors.md)
133 |
134 |
--------------------------------------------------------------------------------