rack-webdav 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/LICENSE +42 -0
- data/README.rdoc +336 -0
- data/bin/rack-webdav +126 -0
- data/lib/rack-webdav.rb +14 -0
- data/lib/rack-webdav/controller.rb +601 -0
- data/lib/rack-webdav/file.rb +37 -0
- data/lib/rack-webdav/file_resource_lock.rb +169 -0
- data/lib/rack-webdav/handler.rb +63 -0
- data/lib/rack-webdav/http_status.rb +108 -0
- data/lib/rack-webdav/interceptor.rb +22 -0
- data/lib/rack-webdav/interceptor_resource.rb +119 -0
- data/lib/rack-webdav/lock.rb +40 -0
- data/lib/rack-webdav/lock_store.rb +61 -0
- data/lib/rack-webdav/logger.rb +30 -0
- data/lib/rack-webdav/remote_file.rb +148 -0
- data/lib/rack-webdav/resource.rb +485 -0
- data/lib/rack-webdav/resources/file_resource.rb +379 -0
- data/lib/rack-webdav/resources/mongo_resource.rb +341 -0
- data/lib/rack-webdav/utils.rb +40 -0
- data/lib/rack-webdav/version.rb +17 -0
- data/rack-webdav.gemspec +31 -0
- metadata +206 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56d779afdbd6da5c459d33219b508ed4b141a564
|
4
|
+
data.tar.gz: 1bba827edea7b0d09f7b22ecb013660966c23ee8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 888809b2b3deebd298ab26810d980686df9cf912ef3f8d557de2e5dfd45a3d0a3fa110dcd8562c4c3c38e6df1137901128eba54021e431139352e1cf0ba1e954
|
7
|
+
data.tar.gz: b545e17b78a6ec5c5c8ff1ae9e6d7cb4e682c152ed1d484ca8b5dd92a6be6599f0b4b68bd23bb72e84ae8013724ea2d280f9800ccc329369eea3ee5762bb2e4a
|
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Current RackWebDAV license:
|
2
|
+
|
3
|
+
Copyright (c) 2010 Chris Roberts <chrisroberts.code@gmail.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to
|
7
|
+
deal in the Software without restriction, including without limitation the
|
8
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
9
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
18
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
|
23
|
+
Original rack_dav source license:
|
24
|
+
|
25
|
+
Copyright (c) 2009 Matthias Georgi <http://www.matthias-georgi.de>
|
26
|
+
|
27
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
28
|
+
of this software and associated documentation files (the "Software"), to
|
29
|
+
deal in the Software without restriction, including without limitation the
|
30
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
31
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
32
|
+
furnished to do so, subject to the following conditions:
|
33
|
+
|
34
|
+
The above copyright notice and this permission notice shall be included in
|
35
|
+
all copies or substantial portions of the Software.
|
36
|
+
|
37
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
38
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
39
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
40
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
41
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
42
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,336 @@
|
|
1
|
+
= RackWebDAV - Web Authoring for Rack
|
2
|
+
|
3
|
+
RackWebDAV based by (dav4rack)[https://github.com/chrisroberts/dav4rack]
|
4
|
+
|
5
|
+
== Motivaion
|
6
|
+
|
7
|
+
* dav4rack no maintained
|
8
|
+
* I want to implment the following functions
|
9
|
+
* WebDAV RFC 3253 ( https://www.ietf.org/rfc/rfc3253.txt )
|
10
|
+
* because support Subversion (SVN)
|
11
|
+
* Rails 5 support
|
12
|
+
* Rack 2.0 support
|
13
|
+
|
14
|
+
== Current Feature
|
15
|
+
|
16
|
+
=== From DAV4Rack
|
17
|
+
* Better resource support for building fully virtualized resource structures
|
18
|
+
* Generic locking as well as Resource level specific locking
|
19
|
+
* Interceptor middleware to provide virtual mapping to resources
|
20
|
+
* Mapped resource paths
|
21
|
+
* Authentication support
|
22
|
+
* Resource callbacks
|
23
|
+
* Remote file proxying (including sendfile support for remote files)
|
24
|
+
|
25
|
+
=== RackWebDAV original
|
26
|
+
* Rack 2.0 support
|
27
|
+
* serveral bugfix
|
28
|
+
|
29
|
+
== Install
|
30
|
+
=== RubyGems
|
31
|
+
|
32
|
+
gem install rack-webdav
|
33
|
+
|
34
|
+
== Documentation
|
35
|
+
|
36
|
+
* TODO
|
37
|
+
|
38
|
+
== Quickstart
|
39
|
+
|
40
|
+
If you just want to share a folder over WebDAV, you can just start a
|
41
|
+
simple server with:
|
42
|
+
|
43
|
+
rack-webdav
|
44
|
+
|
45
|
+
This will start a Unicorn, Mongrel or WEBrick server on port 3000, which you can connect
|
46
|
+
to without authentication. Unicorn and Mongrel will be much more responsive than WEBrick,
|
47
|
+
so if you are having slowness issues, install one of them and restart the rack-webdav process.
|
48
|
+
The simple file resource allows very basic authentication which is used for an example. To enable it:
|
49
|
+
|
50
|
+
rack-webdav --username=user --password=pass
|
51
|
+
|
52
|
+
== Rack Handler
|
53
|
+
|
54
|
+
Using RackWebDAV within a rack application is pretty simple. A very slim
|
55
|
+
rackup script would look something like this:
|
56
|
+
|
57
|
+
require 'rubygems'
|
58
|
+
require 'rack-webdav'
|
59
|
+
|
60
|
+
use Rack::CommonLogger
|
61
|
+
run RackWebDAV::Handler.new(:root => '/path/to/public/fileshare')
|
62
|
+
|
63
|
+
This will use the included FileResource and set the share path. However,
|
64
|
+
RackWebDAV has some nifty little extras that can be enabled in the rackup script. First,
|
65
|
+
an example of how to use a custom resource:
|
66
|
+
|
67
|
+
run RackWebDAV::Handler.new(:resource_class => CustomResource, :custom => 'options', :passed => 'to resource')
|
68
|
+
|
69
|
+
Next, lets venture into mapping a path for our WebDAV access. In this example, we
|
70
|
+
will use default FileResource like in the first example, but instead of the WebDAV content
|
71
|
+
being available at the root directory, we will map it to a specific directory: /webdav/share/
|
72
|
+
|
73
|
+
require 'rubygems'
|
74
|
+
require 'rack-webdav'
|
75
|
+
|
76
|
+
use Rack::CommonLogger
|
77
|
+
|
78
|
+
app = Rack::Builder.new{
|
79
|
+
map '/webdav/share/' do
|
80
|
+
run RackWebDAV::Handler.new(:root => '/path/to/public/fileshare', :root_uri_path => '/webdav/share/')
|
81
|
+
end
|
82
|
+
}.to_app
|
83
|
+
run app
|
84
|
+
|
85
|
+
Aside from the Builder#map block, notice the new option passed to the Handler's initialization, :root_uri_path. When
|
86
|
+
RackWebDAV receives a request, it will automatically convert the request to the proper path and pass it to
|
87
|
+
the resource.
|
88
|
+
|
89
|
+
Another tool available when building the rackup script is the Interceptor. The Interceptor's job is to simply
|
90
|
+
intecept WebDAV requests received up the path hierarchy where no resources are currently mapped. For example,
|
91
|
+
lets continue with the last example but this time include the interceptor:
|
92
|
+
|
93
|
+
require 'rubygems'
|
94
|
+
require 'rack-webdav'
|
95
|
+
|
96
|
+
use Rack::CommonLogger
|
97
|
+
app = Rack::Builder.new{
|
98
|
+
map '/webdav/share/' do
|
99
|
+
run RackWebDAV::Handler.new(:root => '/path/to/public/fileshare', :root_uri_path => '/webdav/share/')
|
100
|
+
end
|
101
|
+
map '/webdav/share2/' do
|
102
|
+
run RackWebDAV::Handler.new(:resource_class => CustomResource, :root_uri_path => '/webdav/share2/')
|
103
|
+
end
|
104
|
+
map '/' do
|
105
|
+
use RackWebDAV::Interceptor, :mappings => {
|
106
|
+
'/webdav/share/' => {:resource_class => FileResource, :custom => 'option'},
|
107
|
+
'/webdav/share2/' => {:resource_class => CustomResource}
|
108
|
+
}
|
109
|
+
use Rails::Rack::Static
|
110
|
+
run ActionController::Dispatcher.new
|
111
|
+
end
|
112
|
+
}.to_app
|
113
|
+
run app
|
114
|
+
|
115
|
+
In this example we have two WebDAV resources restricted by path. This means those resources will handle requests to /webdav/share/*
|
116
|
+
and /webdav/share2/* but nothing above that. To allow webdav to respond, we provide the Interceptor. The Interceptor does not
|
117
|
+
provide any authentication support. It simply creates a virtual file system view to the provided mapped paths. Once the actual
|
118
|
+
resources have been reached, authentication will be enforced based on the requirements defined by the individual resource. Also
|
119
|
+
note in the root map you can see we are running a Rails application. This is how you can easily enable RackWebDAV with your Rails
|
120
|
+
application.
|
121
|
+
|
122
|
+
=== Enabling Logging
|
123
|
+
|
124
|
+
RackWebDAV provides some simple logging in a Rails style format (simply for consistency) so the output should look some what familiar.
|
125
|
+
|
126
|
+
RackWebDAV::Handler.new(:resource_class => CustomResource, :log_to => '/my/log/file')
|
127
|
+
|
128
|
+
You can even specify the level of logging:
|
129
|
+
|
130
|
+
RackWebDAV::Handler.new(:resource_class => CustomResource, :log_to => ['/my/log/file', Logger::DEBUG])
|
131
|
+
|
132
|
+
== Custom Resources
|
133
|
+
|
134
|
+
Creating your own resource is easy. Simply inherit the RackWebDAV::Resource class, and start redefining all the methods
|
135
|
+
you want to customize. The RackWebDAV::Resource class only has implementations for methods that can be provided extremely
|
136
|
+
generically. This means that most things will require at least some sort of implementation. However, because the Resource
|
137
|
+
is defined so generically, and the Controller simply passes the request on to the Resource, it is easy to create fully
|
138
|
+
virtualized resources.
|
139
|
+
|
140
|
+
== Helpers
|
141
|
+
|
142
|
+
There are some helpers worth mentioning that make things a little easier. RackWebDAV::Resource#accept_redirect? method is available to Resources.
|
143
|
+
If true, the currently connected client will accept and properly use a 302 redirect for a GET request. Most clients do not properly
|
144
|
+
support this, which can be a real pain when working with virtualized files that may be located some where else, like S3. To deal with
|
145
|
+
those clients that don't support redirects, a helper has been provided so resources don't have to deal with proxying themselves. The RackWebDAV::RemoteFile
|
146
|
+
is a modified Rack::File that can do some interesting things. First, lets look at its most basic use:
|
147
|
+
|
148
|
+
class MyResource < RackWebDAV::Resource
|
149
|
+
def setup
|
150
|
+
@item = method_to_fill_this_properly
|
151
|
+
end
|
152
|
+
|
153
|
+
def get
|
154
|
+
if(accept_redirect?)
|
155
|
+
response.redirect item[:url]
|
156
|
+
else
|
157
|
+
response.body = RackWebDAV::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type)
|
158
|
+
OK
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
This is a simple proxy. When Rack receives the RemoteFile, it will pull a chunk of data from object, which in turn pulls it from the socket, and
|
164
|
+
sends it to the user over and over again until the EOF is reached. This much the same method that Rack::File uses but instead we are pulling
|
165
|
+
from a socket rather than an actual file. Now, instead of proxying these files from a remote server every time, lets cache them:
|
166
|
+
|
167
|
+
response.body = RackWebDAV::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :cache_directory => '/tmp')
|
168
|
+
|
169
|
+
Providing the :cache_directory will let RemoteFile cache the items locally, and then search for them on subsequent requests before heading out
|
170
|
+
to the network. The cached file name is based off the SHA1 hash of the file path, size and last modified time. It is important to note that for
|
171
|
+
services like S3, the path will often change, making this cache pretty worthless. To combat this, we can provide a reference to use instead:
|
172
|
+
|
173
|
+
response.body = RackWebDAV::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :cache_directory => '/tmp', :cache_ref => item[:static_url])
|
174
|
+
|
175
|
+
These methods will work just fine, but it would be really nice to just let someone else deal with the proxying and let the process get back
|
176
|
+
to dealing with actual requests. RemoteFile will happily do that as long as the frontend server is setup correctly. Using the sendfile approach
|
177
|
+
will tell the RemoteFile to simply pass the headers on and let the server deal with doing the actual proxying. First, lets look at an implementation
|
178
|
+
using all the features, and then degrade that down to the bare minimum. These examples are NGINX specific, but are based off the Rack::Sendfile implementation
|
179
|
+
and as such should be applicable to other servers. First, a simplified NGINX server block:
|
180
|
+
|
181
|
+
server {
|
182
|
+
listen 80;
|
183
|
+
location / {
|
184
|
+
proxy_set_header X-Real-IP $remote_addr;
|
185
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
186
|
+
proxy_set_header Host $http_host;
|
187
|
+
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
|
188
|
+
proxy_set_header X-Accel-Remote-Mapping webdav_redirect
|
189
|
+
proxy_pass http://my_app_server;
|
190
|
+
}
|
191
|
+
|
192
|
+
location ~* /webdav_redirect {
|
193
|
+
internal;
|
194
|
+
resolver 127.0.0.1;
|
195
|
+
set $r_host $upstream_http_redirect_host;
|
196
|
+
set $r_url $upstream_http_redirect_url;
|
197
|
+
proxy_set_header Authorization '';
|
198
|
+
proxy_set_header Host $r_host;
|
199
|
+
proxy_max_temp_file_size 0;
|
200
|
+
proxy_pass $r_url;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
With this in place, the parameters for the RemoteFile change slightly:
|
205
|
+
|
206
|
+
response.body = RackWebDAV::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :sendfile => true)
|
207
|
+
|
208
|
+
The RemoteFile will automatically take care of building out the correct path and sending the proper headers. If the X-Accel-Remote-Mapping header
|
209
|
+
is not available, you can simply pass the value:
|
210
|
+
|
211
|
+
response.body = RackWebDAV::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :sendfile => true, :sendfile_prefix => 'webdav_redirect')
|
212
|
+
|
213
|
+
And if you don't have the X-Sendfile-Type header set, you can fix that by changing the value of :sendfile:
|
214
|
+
|
215
|
+
response.body = RackWebDAV::RemoteFile.new(item[:url], :size => content_length, :mime_type => content_type, :sendfile => 'X-Accel-Redirect', :sendfile_prefix => 'webdav_redirect')
|
216
|
+
|
217
|
+
And if you have none of the above because your server hasn't been configured for sendfile support, you're out of luck until it's configured.
|
218
|
+
|
219
|
+
== Authentication
|
220
|
+
|
221
|
+
Authentication is performed on a per Resource basis. The Controller object will check the Resource for a Resource#authenticate method. If it exists,
|
222
|
+
any authentication information will be passed to the method. Depending on the result, the Controller will either continue on with the request, or send
|
223
|
+
a 401 Unauthorized response.
|
224
|
+
|
225
|
+
As a nicety, Resource#authentication_realm will be checked for existence and the returning string will be used as the Realm. Resource#authentication_error_msg
|
226
|
+
will also be checked for existence and the returning string will be passed in the response upon authentication failure.
|
227
|
+
|
228
|
+
Authentication can also be implemented using callbacks, as discussed below.
|
229
|
+
|
230
|
+
== Callbacks
|
231
|
+
|
232
|
+
Resources can make use of callbacks to easily apply permissions, authentication or any other action that needs to be performed before or after any or all
|
233
|
+
actions. Callbacks are applied to all publicly available methods. This is important for methods used internally within the resource. Methods not meant
|
234
|
+
to be called by the Controller, or anyone else, should be scoped protected or private to reduce the interaction with callbacks.
|
235
|
+
|
236
|
+
Callbacks can be called before or after a method call. For example:
|
237
|
+
|
238
|
+
class MyResource < RackWebDAV::Resource
|
239
|
+
before do |resource, method_name|
|
240
|
+
resource.send(:my_authentication_method)
|
241
|
+
end
|
242
|
+
|
243
|
+
after do |resource, method_name|
|
244
|
+
puts "#{Time.now} -> Completed: #{resource}##{method_name}"
|
245
|
+
end
|
246
|
+
|
247
|
+
private
|
248
|
+
|
249
|
+
def my_authentication_method
|
250
|
+
true
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
In this example MyResource#my_authentication_method will be called before any public method is called. After any method has been called a status
|
255
|
+
line will be printed to STDOUT. Running callbacks before/after every method call is a bit much in most cases, so callbacks can be applied to specific
|
256
|
+
methods:
|
257
|
+
|
258
|
+
class MyResource < RackWebDAV::Resource
|
259
|
+
before_get do |resource|
|
260
|
+
puts "#{Time.now} -> Received GET request from resource: #{resource}"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
In this example, a simple status line will be printed to STDOUT before the MyResource#get method is called. The current resource object is always
|
265
|
+
provided to callbacks. The method name is only provided to the generic before/after callbacks.
|
266
|
+
|
267
|
+
Something very handy for dealing with the mess of files OS X leaves on the system:
|
268
|
+
|
269
|
+
class MyResource < RackWebDAV::Resource
|
270
|
+
after_unlock do |resource|
|
271
|
+
resource.delete if resource.name[0,1] == '.'
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
Because OS X implements locking correctly, we can wait until it releases the lock on the file, and remove it if it's a hidden file.
|
276
|
+
|
277
|
+
Callbacks are called in the order they are defined, so you can easily build callbacks off each other. Like this example:
|
278
|
+
|
279
|
+
class MyResource < RackWebDAV::Resource
|
280
|
+
before do |resource, method_name|
|
281
|
+
resource.DAV_authenticate unless resource.user.is_a?(User)
|
282
|
+
raise Unauthorized unless resource.user.is_a?(User)
|
283
|
+
end
|
284
|
+
before do |resource, method_name|
|
285
|
+
resource.user.allowed?(method_name)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
In this example, the second block checking User#allowed? can count on Resource#user being defined because the blocks are called in
|
290
|
+
order, and if the Resource#user is not a User type, an exception is raised.
|
291
|
+
|
292
|
+
=== Avoiding callbacks
|
293
|
+
|
294
|
+
Something special to notice in the last example is the DAV_ prefix on authenticate. Providing the DAV_ prefix will prevent
|
295
|
+
any callbacks being applied to the given method. This allows us to provide a public method that the callback can access on the resource
|
296
|
+
without getting stuck in a loop.
|
297
|
+
|
298
|
+
== Software using RackWebDAV!
|
299
|
+
|
300
|
+
* {meishi}[https://github.com/inferiorhumanorgans/meishi] - Lightweight CardDAV implementation in Rails
|
301
|
+
* {rack-webdav_ext}[https://github.com/schmurfy/rack-webdav_ext] - CardDAV extension. (CalDAV planned)
|
302
|
+
|
303
|
+
== Issues/Bugs/Questions
|
304
|
+
|
305
|
+
=== Known Issues
|
306
|
+
|
307
|
+
* OS X Finder PUT fails when using NGINX (this is due to NGINX's lack of chunked transfer encoding)
|
308
|
+
* Windows WebDAV mini-redirector fails (this client is very broken. patches welcome.)
|
309
|
+
* Lots of unimplemented parts of the webdav spec (patches always welcome)
|
310
|
+
|
311
|
+
=== Unknown Issues
|
312
|
+
|
313
|
+
Please use the issues at github: http://github.com/chrisroberts/rack-webdav/issues
|
314
|
+
|
315
|
+
== Contributors
|
316
|
+
|
317
|
+
A big thanks to everyone contributing to help make this project better.
|
318
|
+
|
319
|
+
* {clyfe}[http://github.com/clyfe]
|
320
|
+
* {antiloopgmbh}[http://github.com/antiloopgmbh]
|
321
|
+
* {krug}[http://github.com/krug]
|
322
|
+
* {teefax}[http://github.com/teefax]
|
323
|
+
* {buffym}[https://github.com/buffym]
|
324
|
+
* {jbangert}[https://github.com/jbangert]
|
325
|
+
* {doxavore}[https://github.com/doxavore]
|
326
|
+
* {spicyj}[https://github.com/spicyj]
|
327
|
+
* {TurchenkoAlex}[https://github.com/TurchenkoAlex]
|
328
|
+
* {exabugs}[https://github.com/exabugs]
|
329
|
+
* {inferiorhumanorgans}[https://github.com/inferiorhumanorgans]
|
330
|
+
* {schmurfy}[https://github.com/schmurfy]
|
331
|
+
* {pifleo}[https://github.com/pifleo]
|
332
|
+
* {mlmorg}[https://github.com/mlmorg]
|
333
|
+
|
334
|
+
== License
|
335
|
+
|
336
|
+
Just like RackDAV before it, this software is distributed under the MIT license.
|
data/bin/rack-webdav
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rack-webdav/version'
|
5
|
+
require 'getoptlong'
|
6
|
+
|
7
|
+
def print_help_msg
|
8
|
+
print_version_info
|
9
|
+
puts "Usage: rack-webdav [opts]"
|
10
|
+
puts " --help Print help message"
|
11
|
+
puts " --version Print version information"
|
12
|
+
puts " --username name Set username"
|
13
|
+
puts " --password pass Set password"
|
14
|
+
puts " --root /share/path Set path to share directory"
|
15
|
+
puts " --log /path/to/log Set path for logging file"
|
16
|
+
puts " --verbosity opt Set logging verbosity. (Valid: debug,info,warn,fatal)"
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_version_info
|
20
|
+
puts "DAV 4 Rack - Rack based WebDAV Framework - Version: #{RackWebDAV::VERSION}"
|
21
|
+
end
|
22
|
+
|
23
|
+
opts = GetoptLong.new(
|
24
|
+
['--username', '-u', GetoptLong::REQUIRED_ARGUMENT],
|
25
|
+
['--password', '-p', GetoptLong::REQUIRED_ARGUMENT],
|
26
|
+
['--help', '-h', GetoptLong::NO_ARGUMENT],
|
27
|
+
['--version', '-v', GetoptLong::NO_ARGUMENT],
|
28
|
+
['--root', '-r', GetoptLong::REQUIRED_ARGUMENT],
|
29
|
+
['--log', '-l', GetoptLong::OPTIONAL_ARGUMENT],
|
30
|
+
['--verbosity', '-V', GetoptLong::REQUIRED_ARGUMENT],
|
31
|
+
['--pretty-xml', '-P', GetoptLong::REQUIRED_ARGUMENT]
|
32
|
+
)
|
33
|
+
|
34
|
+
credentials = {}
|
35
|
+
|
36
|
+
opts.each do |opt,arg|
|
37
|
+
case opt
|
38
|
+
when '--help'
|
39
|
+
print_help_msg
|
40
|
+
exit(0)
|
41
|
+
when '--username'
|
42
|
+
credentials[:username] = arg
|
43
|
+
when '--password'
|
44
|
+
credentials[:password] = arg
|
45
|
+
when '--root'
|
46
|
+
credentials[:root] = arg
|
47
|
+
unless(File.exists?(arg) && File.directory?(arg))
|
48
|
+
puts "ERROR: Path provided is not a valid directory (#{arg})"
|
49
|
+
exit(-1)
|
50
|
+
end
|
51
|
+
when '--pretty-xml'
|
52
|
+
credentials[:pretty_xml] = true
|
53
|
+
when '--version'
|
54
|
+
print_version_info
|
55
|
+
exit(0)
|
56
|
+
when '--log'
|
57
|
+
require 'pathname'
|
58
|
+
require 'logger'
|
59
|
+
credentials[:log_to] = [nil, Logger::FATAL] unless credentials[:log_to]
|
60
|
+
if(arg && !arg.empty?)
|
61
|
+
dirname = Pathname.new(arg).dirname
|
62
|
+
if((File.exists?(arg) && File.writable?(arg)) || (File.exists?(dirname) && File.writable?(dirname)))
|
63
|
+
credentials[:log_to][0] = arg
|
64
|
+
else
|
65
|
+
puts "ERROR: Log file is not writable: #{arg}"
|
66
|
+
exit(-1)
|
67
|
+
end
|
68
|
+
else
|
69
|
+
credentials[:log_to][0] = $stdout
|
70
|
+
end
|
71
|
+
when '--verbosity'
|
72
|
+
require 'logger'
|
73
|
+
begin
|
74
|
+
credentials[:log_to] = [] unless credentials[:log_to]
|
75
|
+
credentials[:log_to][1] = Logger.const_get(arg.upcase)
|
76
|
+
rescue NameError
|
77
|
+
puts "ERROR: Unknown verbosity level given: #{arg}"
|
78
|
+
exit(-1)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
puts "ERROR: Unknown option provided"
|
82
|
+
exit(-1)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
require 'rack-webdav'
|
87
|
+
|
88
|
+
app = Rack::Builder.new do
|
89
|
+
use Rack::ShowExceptions
|
90
|
+
use Rack::CommonLogger
|
91
|
+
use Rack::Reloader
|
92
|
+
use Rack::Lint
|
93
|
+
|
94
|
+
run RackWebDAV::Handler.new(credentials)
|
95
|
+
|
96
|
+
end.to_app
|
97
|
+
|
98
|
+
runners = []
|
99
|
+
runners << lambda do |x|
|
100
|
+
print 'Looking for unicorn... '
|
101
|
+
require 'unicorn'
|
102
|
+
puts 'OK'
|
103
|
+
if(Unicorn.respond_to?(:run))
|
104
|
+
Unicorn.run(x, :listeners => ["0.0.0.0:3000"])
|
105
|
+
else
|
106
|
+
Unicorn::HttpServer.new(x, :listeners => ["0.0.0.0:3000"]).start.join
|
107
|
+
end
|
108
|
+
end
|
109
|
+
runners << lambda do |x|
|
110
|
+
print 'Looking for mongrel... '
|
111
|
+
require 'mongrel'
|
112
|
+
puts 'OK'
|
113
|
+
Rack::Handler::Mongrel.run(x, :Port => 3000)
|
114
|
+
end
|
115
|
+
runners << lambda do |x|
|
116
|
+
puts 'Loading WEBrick'
|
117
|
+
Rack::Handler::WEBrick.run(x, :Port => 3000)
|
118
|
+
end
|
119
|
+
|
120
|
+
begin
|
121
|
+
runner = runners.shift
|
122
|
+
runner.call(app)
|
123
|
+
rescue LoadError
|
124
|
+
puts 'FAILED'
|
125
|
+
retry unless runners.empty?
|
126
|
+
end
|