dropboxuploader 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+