dropboxuploader 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.rdoc +16 -0
  2. data/lib/dropbox_uploader.rb +245 -0
  3. metadata +63 -0
data/README.rdoc ADDED
@@ -0,0 +1,16 @@
1
+ == About this library
2
+
3
+ A simple Dropbox ( http://www.dropbox.com/ ) library to upload files, with no other gem dependencies.
4
+ This library has been completely written from scratch, but ideas and logics
5
+ are inspired from Dropbox Uploader ( http://jaka.kubje.org/software/DropboxUploader/ ).
6
+
7
+ == Example
8
+
9
+ require "dropbox_uploader"
10
+ dropbox = DropboxUploader.new("email@example.com", "MyPassword")
11
+ dropbox.upload("localfile.txt", "/")
12
+
13
+ == Known bugs
14
+
15
+ * error check and recovery
16
+ * non-ASCII file/remotedir name support
@@ -0,0 +1,245 @@
1
+ # Dropbox upload library for Ruby
2
+ #
3
+ # Copyright (c) 2009 NAKAMURA Usaku <usa@garbagecollect.jp>
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
20
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23
+ # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26
+ # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
28
+
29
+ require "net/https"
30
+ require "uri"
31
+
32
+ # == About this library
33
+ #
34
+ # A simple Dropbox ( http://www.dropbox.com/ ) library to upload files, with no other gem dependencies.
35
+ # This library has been completely written from scratch, but ideas and logics
36
+ # are inspired from Dropbox Uploader ( http://jaka.kubje.org/software/DropboxUploader/ ).
37
+ #
38
+ # == Example
39
+ #
40
+ # require "dropbox_uploader"
41
+ # dropbox = DropboxUploader.new("email@exapmle.com", "MyPassword")
42
+ # dropbox.upload("localfile.txt", "/")
43
+ #
44
+ # == Known bugs
45
+ #
46
+ # * error check and recovery
47
+ # * non-ASCII file/remotedir name support
48
+ #
49
+ class DropboxUploader
50
+ #
51
+ # Create Dropbox instance and initialize it.
52
+ # _email_ is your email registered at Dropobox.
53
+ # _pass_ is your password, too.
54
+ # _capath_ is the path of directory of CA files.
55
+ #
56
+ def initialize(email, pass, capath = nil)
57
+ @email = email
58
+ @pass = pass
59
+ @ca = capath
60
+ @cookie = nil
61
+ @login = false
62
+ end
63
+
64
+ # :nodoc:
65
+ def login
66
+ html = send_request("https://www.dropbox.com/login").body
67
+ token = extract_token(html, "/login")
68
+ raise "token not found on /login" unless token
69
+ res = send_request("https://www.dropbox.com/login", "login_email" => @email, "login_password" => @pass, "t" => token)
70
+ if res["location"] == "/home"
71
+ @login = true
72
+ else
73
+ raise "login failed #{res.code}:#{res.message}"
74
+ end
75
+ end
76
+
77
+ #
78
+ # Upload local file to Dropbox remote directory.
79
+ # _file_ is a local file path.
80
+ # _remote_ is the target remote directory.
81
+ #
82
+ def upload(file, remote)
83
+ login unless @login
84
+ html = send_request("https://www.dropbox.com/home?upload=1").body
85
+ token = extract_token(html, "https://dl-web.dropbox.com/upload")
86
+ raise "token not found on /upload" unless token
87
+
88
+ stream = open(file, "rb")
89
+ rawdata = stream.read
90
+ filesize = rawdata.size
91
+ boundary = generate_boundary(rawdata)
92
+ rawdata = nil
93
+ stream.rewind
94
+
95
+ pre = ""
96
+ {"dest" => remote, "t" => token}.each do |k,v|
97
+ pre << "--#{boundary}\r\n"
98
+ pre << %'Content-Disposition: form-data; name="#{k}"\r\n'
99
+ pre << "\r\n"
100
+ pre << %'#{v}\r\n'
101
+ end
102
+ pre << "--#{boundary}\r\n"
103
+ pre << %'Content-Disposition: form-data; name="file"; filename="#{File.basename(file)}"\r\n'
104
+ pre << "Content-Type: application/octet-stream\r\n"
105
+ pre << "\r\n"
106
+
107
+ post = "\r\n"
108
+ post << "--#{boundary}--\r\n"
109
+
110
+ data = PseudoIO.new(pre, [stream, filesize], post)
111
+
112
+ res = send_request("https://dl-web.dropbox.com/upload", data, boundary)
113
+ if res.code[0] != ?2 && res.code[0] != ?3
114
+ raise "upload failed #{res.code}:#{res.message}"
115
+ end
116
+
117
+ true
118
+ end
119
+
120
+ private
121
+ # :nodoc:
122
+ def send_request(url, params = nil, boundary = nil)
123
+ uri = URI.parse(url)
124
+ https = Net::HTTP.new(uri.host, uri.port)
125
+ https.use_ssl = true
126
+ if @ca
127
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
128
+ https.ca_path = @ca
129
+ else
130
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
131
+ end
132
+ result = nil
133
+ https.start do
134
+ if @cookie
135
+ header = {"Cookie" => @cookie}
136
+ else
137
+ header = {}
138
+ end
139
+
140
+ if params
141
+ if boundary
142
+ header["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
143
+ req = Net::HTTP::Post.new(uri.path, header)
144
+ req.body_stream = params
145
+ req["Content-Length"] = params.size
146
+ result = https.request(req)
147
+ else
148
+ result = https.post(uri.path, params.map{|k,v| URI.encode("#{k}=#{v}")}.join("&"), header)
149
+ end
150
+ else
151
+ result = https.get(uri.path, header)
152
+ end
153
+ @cookie = result["set-cookie"] if result["set-cookie"]
154
+ end
155
+ result
156
+ end
157
+
158
+ # :nodoc:
159
+ def extract_token(html, action)
160
+ #puts html
161
+ return nil unless %r'<form action="#{action}"(.+?)</form>'m =~ html
162
+ scrap = $1
163
+ return nil unless /name="t" value="(.+?)"/ =~ scrap
164
+ return $1
165
+ end
166
+
167
+ # :nodoc:
168
+ def generate_boundary(str)
169
+ begin
170
+ boundary = "RubyDropbox#{rand(2**8).to_s(16)}"
171
+ end while str.include?(boundary)
172
+ boundary
173
+ end
174
+ end
175
+
176
+ #
177
+ # This class provides a pseudo read-only IO, constructed from some strings and
178
+ # ios.
179
+ #
180
+ class PseudoIO
181
+ require "stringio"
182
+
183
+ #
184
+ # PseudoIO.new(string or array, ...)
185
+ #
186
+ # string : an instance of String
187
+ # array : [stream, size]
188
+ #
189
+ def initialize(*args)
190
+ @totalsize = 0
191
+ @ios = []
192
+ args.each do |arg|
193
+ if arg.is_a? String
194
+ @ios << StringIO.new(arg)
195
+ @totalsize += arg.size
196
+ else
197
+ @ios << arg[0]
198
+ @totalsize += arg[1]
199
+ end
200
+ end
201
+ end
202
+
203
+ #
204
+ # pseudoIo.size -> integer
205
+ #
206
+ # Returns the total size of strings and streams
207
+ #
208
+ def size
209
+ @totalsize
210
+ end
211
+ alias length size
212
+
213
+ #
214
+ # pseudoIo.read([size, [buffer]]) -> string, buffer, or nil
215
+ #
216
+ # See IO#read.
217
+ #
218
+ def read(size = nil, result = nil)
219
+ if result
220
+ result.replace('')
221
+ else
222
+ result = ''
223
+ end
224
+ if size
225
+ return nil if @ios.empty?
226
+ until @ios.empty?
227
+ cur = @ios.first.read(size)
228
+ if cur
229
+ result << cur
230
+ break if cur.size >= size
231
+ size -= cur.size
232
+ end
233
+ @ios.shift.close
234
+ end
235
+ else
236
+ return "" if @ios.empty?
237
+ until @ios.empty?
238
+ io = @ios.shift
239
+ result << io.read
240
+ io.close
241
+ end
242
+ end
243
+ result
244
+ end
245
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dropboxuploader
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - unak,luisbebop
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-23 00:00:00 -03:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: A simple Dropbox library to upload files, with no other gem dependencies.
22
+ email: luisbebop@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - README.rdoc
31
+ - lib/dropbox_uploader.rb
32
+ has_rdoc: true
33
+ homepage: http://github.com/luisbebop/dropbox
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.3.6
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: A simple Dropbox library to upload files.
62
+ test_files: []
63
+