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.
- data/README.rdoc +16 -0
- data/lib/dropbox_uploader.rb +245 -0
- 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
|
+
|