oddjob 1.6.0
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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +19 -0
- data/README.md +147 -0
- data/Rakefile +6 -0
- data/bin/oddjob +151 -0
- data/lib/oddjob/version.rb +3 -0
- data/lib/oddjob.rb +288 -0
- data/oddjob.gemspec +40 -0
- metadata +110 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 38b952a30ef59eab2aecda48c84c792a02daff9e
|
|
4
|
+
data.tar.gz: 6d0f3456c227c1bef0888db3971a80671054ba1d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 71b6164c4462f00a4e7c6cb6385eec124b2d13aea477301ae205d4aac46ed288293ada192acc5499bfa106963ee2edca41e422da83bcd6f54dac620c55c09ef8
|
|
7
|
+
data.tar.gz: aab8882dd01c9585ec228f6a3ba481f9f746b0e906345bbef4fd7f3ae00817ce74fde44c3e9a38feffba4b58bcd8cc340934b26538165a138c3f4af582b8b68b
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) Mike Fellows
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
18
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
19
|
+
DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# oddjob #
|
|
2
|
+
|
|
3
|
+
oddjob is a lightweight, command line controlled web server. Built for
|
|
4
|
+
development and testing purposes, it can be used to serve static content for
|
|
5
|
+
local web development and has basic file upload capabilities. It was initially
|
|
6
|
+
created when web browsers become more restrictive about displaying local files
|
|
7
|
+
directly (*i.e.* file:// URLs).
|
|
8
|
+
|
|
9
|
+
oddjob's file upload endpoint can be used directly via forms or ajax request you
|
|
10
|
+
build yourself with a POST to the `/oj_upload` URL. A basic file upload form
|
|
11
|
+
is also available via a GET request to that same URL. Upon upload the default
|
|
12
|
+
behaviour is for the server to dump the entire upload POST request (header and
|
|
13
|
+
body), followed by the contents of each uploaded file to STDOUT. This is
|
|
14
|
+
useful for small tests uploading text files, but if you need to upload larger
|
|
15
|
+
or binary format files tell oddjob to save the files to a directory instead. If
|
|
16
|
+
you upload and save the same file twice oddjob will not overwrite existing
|
|
17
|
+
saved files, instead a unique name is generated by adding a number to the end
|
|
18
|
+
of the file's name.
|
|
19
|
+
|
|
20
|
+
It is easy to hack the oddjob script to build quick test jigs for web
|
|
21
|
+
development. Sometimes using a simple test web server is easier than working
|
|
22
|
+
with a full fledged development or production environment. To hack the code
|
|
23
|
+
download from the [github repo](https://github.com/MCF/oddjob) and run oddjob
|
|
24
|
+
out of the included `bin` directory.
|
|
25
|
+
|
|
26
|
+
## Installation ##
|
|
27
|
+
|
|
28
|
+
oddjob is available as a ruby gem. To install it for general command line
|
|
29
|
+
use simply use gem like so:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
gem install oddjob
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
In the unlikely event you would like it tied to a project add the following
|
|
36
|
+
line to the project's Gemfile:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
gem 'oddjob'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
And then execute:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
bundle
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
You can also run oddjob directly from the git repo. Clone the git repo and run
|
|
49
|
+
oddjob directly from the repo's bin directory.
|
|
50
|
+
|
|
51
|
+
## Usage ##
|
|
52
|
+
|
|
53
|
+
Command line usage is:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
oddjob [OPTIONS] [server_root]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Where the optional server_root argument will be the server's root directory.
|
|
60
|
+
The default server root is the current working directory.
|
|
61
|
+
|
|
62
|
+
The default file upload behaviour will print the contents of the HTTP POST
|
|
63
|
+
request, and the contents of any uploaded files, to the server's STDOUT. It is
|
|
64
|
+
recommended that you only upload text files in this case. If an output
|
|
65
|
+
directory is specified all uploaded files are saved under their own names in
|
|
66
|
+
this directory. Pre-existing files are not overwritten, instead a number is
|
|
67
|
+
added to the end of the new file names when saving.
|
|
68
|
+
|
|
69
|
+
If a simulated network delay is specified the server will pause that many
|
|
70
|
+
seconds before returning a response for file(s) uploaded to the file upload
|
|
71
|
+
path: `/oj_upload`.
|
|
72
|
+
|
|
73
|
+
The server will only respond to clients on localhost unless the `--allhosts`
|
|
74
|
+
option is specified. Be aware of the security implications of allowing any
|
|
75
|
+
other host on your network to connect to the server if you use this option.
|
|
76
|
+
|
|
77
|
+
An informational page is available at the `/oj_info` path that includes the
|
|
78
|
+
command line usage.
|
|
79
|
+
|
|
80
|
+
The default server port is 4400.
|
|
81
|
+
|
|
82
|
+
Command line options:
|
|
83
|
+
|
|
84
|
+
-d, --delay=value File upload simulated network delay
|
|
85
|
+
-a, --allhosts Allow connections from all hosts
|
|
86
|
+
-o, --output=value Directory to save uploaded files
|
|
87
|
+
-p, --port=value Web server port to use
|
|
88
|
+
--version Display the version number and exit
|
|
89
|
+
|
|
90
|
+
-h, --help Display the usage message
|
|
91
|
+
|
|
92
|
+
To stop oddjob use the normal interrupt key combination (usually Ctrl-C).
|
|
93
|
+
|
|
94
|
+
## Examples ##
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
oddjob
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Serves the files and directories in your current working directory at the
|
|
101
|
+
`http://localhost:4400/` URL. File upload is available at
|
|
102
|
+
`http://localhost:4400/oj_upload`
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
oddjob -p 2222 -o ./uploads ./my-site
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Serves the contents of the `./my-site` directory at the
|
|
109
|
+
`http://localhost:2222/` URL, file upload is available at
|
|
110
|
+
`http://localhost:2222/oj_upload` files are saved to the
|
|
111
|
+
`./uploads` directory.
|
|
112
|
+
|
|
113
|
+
## Environment ##
|
|
114
|
+
|
|
115
|
+
oddjob is written in ruby and its only required dependency is a standard ruby
|
|
116
|
+
install. oddjob makes use of the built in ruby's
|
|
117
|
+
[webrick](http://ruby-doc.org/stdlib-2.0.0/libdoc/webrick/rdoc/WEBrick.html)
|
|
118
|
+
web server library. No gems are required for running oddjob. oddjob has been
|
|
119
|
+
tested with ruby 1.8.7 and up.
|
|
120
|
+
|
|
121
|
+
## Security ##
|
|
122
|
+
|
|
123
|
+
By default oddjob serves to clients on localhost only (that is: browsers
|
|
124
|
+
running on the same computer as oddjob). If the `-a` option is used connections
|
|
125
|
+
from any client on your network are allowed. If you do not trust the users on
|
|
126
|
+
your local network the `-a` option could be a security concern. Anyone who can
|
|
127
|
+
connect to your IP address can browse and download the files served by oddjob.
|
|
128
|
+
|
|
129
|
+
oddjob will serve the contents of the directory specified on the command line,
|
|
130
|
+
or the current working directory if no directory is specified. It does no
|
|
131
|
+
filtering on the contents of the directory served, and the entire directory
|
|
132
|
+
tree below the top level directory is available for browsing.
|
|
133
|
+
|
|
134
|
+
## License ##
|
|
135
|
+
|
|
136
|
+
oddjob is released under an [MIT style license](MIT-LICENSE).
|
|
137
|
+
|
|
138
|
+
## Development ##
|
|
139
|
+
|
|
140
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run
|
|
141
|
+
`rake spec` to run the tests. Oddjob can be run directly from the repo's bin
|
|
142
|
+
directory for easy testing.
|
|
143
|
+
|
|
144
|
+
## Contributing ##
|
|
145
|
+
|
|
146
|
+
Bug reports and pull requests are welcome on GitHub at
|
|
147
|
+
https://github.com/MCF/oddjob.
|
data/Rakefile
ADDED
data/bin/oddjob
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# Copyright (c) Mike Fellows
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
21
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
22
|
+
# DEALINGS IN THE SOFTWARE.
|
|
23
|
+
#++
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
require 'rubygems' # Ruby 1.8.7 compatible.
|
|
27
|
+
gem 'rake'
|
|
28
|
+
rescue LoadError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
begin
|
|
32
|
+
require 'oddjob' # Installed as a gem.
|
|
33
|
+
rescue LoadError
|
|
34
|
+
lib = File.expand_path('../lib', File.dirname( __FILE__))
|
|
35
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
36
|
+
|
|
37
|
+
require 'oddjob' # Simply run from the repo, no gems.
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def show_version
|
|
41
|
+
STDOUT.puts("Version: #{OddJob::VERSION}")
|
|
42
|
+
exit
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def error(msg, suggest_usage = false)
|
|
46
|
+
STDERR.puts("ERORR: #{msg}")
|
|
47
|
+
STDERR.puts(" try the -h option for the command usage") if suggest_usage
|
|
48
|
+
exit 1
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
require 'optparse'
|
|
52
|
+
|
|
53
|
+
opts = {}
|
|
54
|
+
|
|
55
|
+
optparser = OptionParser.new do |o|
|
|
56
|
+
o.banner = "Usage: #{File.basename($0)} [OPTIONS] [server_root]"
|
|
57
|
+
o.separator <<TXT
|
|
58
|
+
|
|
59
|
+
Where the optional server_root argument will be the server's root directory.
|
|
60
|
+
The default server root is the current working directory.
|
|
61
|
+
|
|
62
|
+
The default file upload behaviour will print the contents of the HTTP POST
|
|
63
|
+
request, and the contents of any uploaded files, to the server's STDOUT. It is
|
|
64
|
+
recommended that you only upload text files in this case. If an output
|
|
65
|
+
directory is specified all uploaded files are saved under their own names in
|
|
66
|
+
this directory. Pre-existing files are not overwritten, instead a number is
|
|
67
|
+
added to the end of the new file names when saving.
|
|
68
|
+
|
|
69
|
+
If a simulated network delay is specified the server will pause that many
|
|
70
|
+
seconds before returning a response for file(s) uploaded to the file upload
|
|
71
|
+
path: #{OddJob::UPLOAD_PATH}.
|
|
72
|
+
|
|
73
|
+
The server will only respond to clients on localhost unless the --allhosts
|
|
74
|
+
option is specified. Be aware of the security implications of allowing any
|
|
75
|
+
other host on your network to connect to the server if you use this option.
|
|
76
|
+
|
|
77
|
+
An informational page is available at the #{OddJob::INFO_PATH} path.
|
|
78
|
+
|
|
79
|
+
The default server port is #{OddJob::DEFAULT_PORT}.
|
|
80
|
+
|
|
81
|
+
To stop the server use the normal interrupt key combination (usually Ctrl-C).
|
|
82
|
+
|
|
83
|
+
TXT
|
|
84
|
+
|
|
85
|
+
o.on('-d', '--delay=value', Float,
|
|
86
|
+
'File upload simulated network delay') { |x| opts[:networkdelay] = x }
|
|
87
|
+
o.on('-a', '--allhosts',
|
|
88
|
+
'Allow connections from all hosts') { opts[:allowall] = true }
|
|
89
|
+
o.on('-o', '--output=value', String,
|
|
90
|
+
'Directory to save uploaded files') { |x| opts[:savedirectory] = x }
|
|
91
|
+
o.on('-p', '--port=value', Integer,
|
|
92
|
+
"Web server port to use") { |x| opts[:port] = x }
|
|
93
|
+
o.on('--version',
|
|
94
|
+
'Display the version number and exit') { show_version() }
|
|
95
|
+
|
|
96
|
+
o.separator("")
|
|
97
|
+
|
|
98
|
+
o.on('-h', '--help', 'Display this message') { puts(o); exit }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
theRest = []
|
|
102
|
+
begin
|
|
103
|
+
theRest = optparser.parse(ARGV)
|
|
104
|
+
rescue
|
|
105
|
+
error($!.to_s, true)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
error("too many arguments given", true) if theRest.size > 1
|
|
109
|
+
|
|
110
|
+
if theRest.size == 1
|
|
111
|
+
opts[:serverroot] = theRest.pop
|
|
112
|
+
|
|
113
|
+
unless File.directory?(opts[:serverroot])
|
|
114
|
+
error([
|
|
115
|
+
"directory to serve does not exist or is not ",
|
|
116
|
+
"a directory: #{opts[:serverroot]}"
|
|
117
|
+
].join(''))
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
if opts[:savedirectory] and not File.directory?(opts[:savedirectory])
|
|
121
|
+
error([
|
|
122
|
+
"output directory does not exist or is not ",
|
|
123
|
+
"a directory: #{opts[:savedirectory]}"
|
|
124
|
+
].join(''))
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if opts.has_key?(:port) and (opts[:port] < 0 or opts[:port] > 65535)
|
|
129
|
+
error("port specified is invalid: #{opts[:port]}")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if opts.has_key?(:networkdelay) and opts[:networkdelay] < 0
|
|
133
|
+
error("simulated delay cannot be negative: #{opts[:networkdelay]}")
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
opts[:usagemessage] = optparser.to_s
|
|
137
|
+
|
|
138
|
+
begin
|
|
139
|
+
OddJob.server(opts)
|
|
140
|
+
rescue Errno::EADDRINUSE => e
|
|
141
|
+
error([
|
|
142
|
+
"Could not bind to the port because it is already in use, ",
|
|
143
|
+
"port: #{opts[:port].nil? ? OddJob::DEFAULT_PORT : opts[:port]}"
|
|
144
|
+
].join("\n"))
|
|
145
|
+
rescue Errno::EACCES => e
|
|
146
|
+
error([
|
|
147
|
+
"Could not bind to the port due to insufficient permission, usually",
|
|
148
|
+
"this happens when a non root user attempts to use a privileged port",
|
|
149
|
+
"(between 1 and 1000). Port requested: #{opts[:port]}"
|
|
150
|
+
].join("\n"))
|
|
151
|
+
end
|
data/lib/oddjob.rb
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) Mike Fellows
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
19
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
20
|
+
# DEALINGS IN THE SOFTWARE.
|
|
21
|
+
#++
|
|
22
|
+
|
|
23
|
+
require 'webrick'
|
|
24
|
+
require 'oddjob/version'
|
|
25
|
+
|
|
26
|
+
module OddJob
|
|
27
|
+
|
|
28
|
+
UPLOAD_PATH = '/oj_upload'
|
|
29
|
+
INFO_PATH = '/oj_info'
|
|
30
|
+
DEFAULT_PORT = 4400
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# Start the oddjob server.
|
|
34
|
+
#
|
|
35
|
+
# +opts+ is a hash. Allowed keys are:
|
|
36
|
+
#
|
|
37
|
+
# * +:serverroot+ - directory to serve (default CWD)
|
|
38
|
+
# * +:savedirectory+ - where to save uploads (default dump to STDOUT)
|
|
39
|
+
# * +:usagemessage+ - the command line usage message to dispaly on info page
|
|
40
|
+
# * +:allowall+ - serve to clients other than on localhost? (default false)
|
|
41
|
+
# * +:networkdelay+ - simulated network delay (default no delay).
|
|
42
|
+
# * +:port+ - port to use. (default is in DEFAULT_PORT module constant)
|
|
43
|
+
#
|
|
44
|
+
# Runs the server until a TERM or INT signal is received (e.g. ctrl-c from
|
|
45
|
+
# the command line).
|
|
46
|
+
def OddJob.server(opts)
|
|
47
|
+
defaults = {
|
|
48
|
+
:serverroot => ".",
|
|
49
|
+
:savedirectory => nil,
|
|
50
|
+
:usagemessage => nil,
|
|
51
|
+
:allowall => false,
|
|
52
|
+
:networkdelay => 0,
|
|
53
|
+
:port => DEFAULT_PORT
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
options = defaults.merge(opts)
|
|
57
|
+
|
|
58
|
+
# Add any missing MIME types (http://bugs.ruby-lang.org/issues/5365)
|
|
59
|
+
m_types = WEBrick::HTTPUtils::DefaultMimeTypes.dup
|
|
60
|
+
m_types['js'] = 'application/javascript' unless m_types.has_key?('js')
|
|
61
|
+
m_types['svg'] = 'image/svg+xml' unless m_types.has_key?('svg')
|
|
62
|
+
|
|
63
|
+
server = WEBrick::HTTPServer.new(
|
|
64
|
+
:Port => options[:port],
|
|
65
|
+
:BindAddress => options[:allowall] ? '0.0.0.0' : '127.0.0.1',
|
|
66
|
+
:MimeTypes => m_types,
|
|
67
|
+
:DocumentRoot => options[:serverroot]
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
server.mount(
|
|
71
|
+
INFO_PATH,
|
|
72
|
+
Info,
|
|
73
|
+
options[:usagemessage]
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
server.mount(
|
|
77
|
+
UPLOAD_PATH,
|
|
78
|
+
FileUpload,
|
|
79
|
+
options[:networkdelay],
|
|
80
|
+
options[:savedirectory]
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
['TERM', 'INT'].each { |signal| trap(signal){ server.shutdown } }
|
|
84
|
+
|
|
85
|
+
server.start
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
##
|
|
89
|
+
# A very basic utility for rendering OddJob specific pages.
|
|
90
|
+
|
|
91
|
+
module HtmlRender
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# Wrap +content+ in the standard page layout. +title+ is set as the HTML
|
|
95
|
+
# page's title.
|
|
96
|
+
def page(content, title)
|
|
97
|
+
[
|
|
98
|
+
"<!DOCTYPE html>",
|
|
99
|
+
"<head>",
|
|
100
|
+
" <title>OJ #{title}</title>",
|
|
101
|
+
" <style>",
|
|
102
|
+
" body {font:100% arial,sans-serif; margin:1.5em 5em 4em 5em;}",
|
|
103
|
+
" a {text-decoration:none; color:rgb(248,157,30)}",
|
|
104
|
+
" a:hover {color:rgb(239,131,0);}",
|
|
105
|
+
" .header {font-size:0.75em; float:right; margin-bottom: 2.0em;}",
|
|
106
|
+
" </style>",
|
|
107
|
+
"</head>",
|
|
108
|
+
"<html><body>",
|
|
109
|
+
" <div class=\"header\">",
|
|
110
|
+
" <a href=\"https://github.com/MCF/oddjob\">OddJob on github</a>",
|
|
111
|
+
" </div>",
|
|
112
|
+
" <div style=\"clear:both;\"></div>",
|
|
113
|
+
content.kind_of?(Array) ? content.join("\n") : content,
|
|
114
|
+
"</body></html>",
|
|
115
|
+
].join("\n")
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
# Webrick servlet for creating the information page.
|
|
121
|
+
|
|
122
|
+
class Info < WEBrick::HTTPServlet::AbstractServlet
|
|
123
|
+
include HtmlRender
|
|
124
|
+
|
|
125
|
+
##
|
|
126
|
+
# Standard servlet initialization function with an additional
|
|
127
|
+
# +cmd_usage+ argument for specifying the command line usage
|
|
128
|
+
# of the OddJob module's calling entity.
|
|
129
|
+
def initialize(server, cmd_usage, *options)
|
|
130
|
+
@usage = cmd_usage
|
|
131
|
+
super(server, options)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
##
|
|
135
|
+
# Respond to get request, returns informational page.
|
|
136
|
+
def do_GET(request, response)
|
|
137
|
+
response.status = 200
|
|
138
|
+
response['Content-Type'] = "text/html"
|
|
139
|
+
response.body = info_page
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
protected
|
|
143
|
+
|
|
144
|
+
##
|
|
145
|
+
# Render the HTML for the informational page.
|
|
146
|
+
def info_page
|
|
147
|
+
html = [
|
|
148
|
+
" <h1>#{File.basename($0)}</h1>",
|
|
149
|
+
" <p>Version: <strong>#{VERSION}</strong></p>"
|
|
150
|
+
]
|
|
151
|
+
html << " <pre>#{@usage}</pre>" unless @usage.nil?
|
|
152
|
+
page(html, "Info")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
##
|
|
158
|
+
# Webrick servlet for upload pages.
|
|
159
|
+
|
|
160
|
+
class FileUpload < WEBrick::HTTPServlet::AbstractServlet
|
|
161
|
+
include HtmlRender
|
|
162
|
+
|
|
163
|
+
##
|
|
164
|
+
# Standard servlet initialization function with additional arguments.
|
|
165
|
+
#
|
|
166
|
+
# +delay+ is the seconds of simulated network delay to wait before
|
|
167
|
+
# responding after an upload request.
|
|
168
|
+
#
|
|
169
|
+
# +save_directory+ is the the directory location to save uploaded files.
|
|
170
|
+
# If +save_directory+ is set to nil uploaded files are not save, instead
|
|
171
|
+
# the entire http request is printed on STDOUT, followed by the name and
|
|
172
|
+
# contents of each file. Generally only useful for small and non-binary
|
|
173
|
+
# files.
|
|
174
|
+
def initialize(server, delay, save_directory, *options)
|
|
175
|
+
@simulated_delay = delay
|
|
176
|
+
@save_directory = save_directory
|
|
177
|
+
super(server, options)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
##
|
|
181
|
+
# Handles webrick post request when uploading one or more files via a
|
|
182
|
+
# standard HTML form submission. The form should include an input of type
|
|
183
|
+
# 'file'. See the page produced by the do_GET method for an example form.
|
|
184
|
+
def do_POST(request, response)
|
|
185
|
+
|
|
186
|
+
if @save_directory.nil? # Request to server STDOUT.
|
|
187
|
+
puts "-- BEGIN File Upload POST Request --"
|
|
188
|
+
puts request
|
|
189
|
+
puts "-- END File Upload POST Request --"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
all_files = Array.new
|
|
193
|
+
['file', 'file[]'].each do |name|
|
|
194
|
+
if request.query[name]
|
|
195
|
+
request.query[name].each_data do |data|
|
|
196
|
+
|
|
197
|
+
all_files.push(data.filename)
|
|
198
|
+
|
|
199
|
+
if @save_directory.nil? # File contents to server STDOUT.
|
|
200
|
+
puts "== BEGIN #{data.filename} Contents =="
|
|
201
|
+
puts data.to_s
|
|
202
|
+
puts "== END #{data.filename} Contents =="
|
|
203
|
+
else
|
|
204
|
+
output_name = unique_name(data.filename, @save_directory)
|
|
205
|
+
File.open(output_name, "w"){|f| f.print(data.to_s)}
|
|
206
|
+
puts "#{data.filename} uploaded, saved to #{output_name}"
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
response.status = 200
|
|
213
|
+
response['Content-type'] = 'text/html'
|
|
214
|
+
response.body = uploaded_page(all_files)
|
|
215
|
+
|
|
216
|
+
sleep(@simulated_delay)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
##
|
|
220
|
+
# Serves a simple file upload form. Uploads submitted are handled by this
|
|
221
|
+
# class' +do_Post+ method.
|
|
222
|
+
def do_GET(request, response)
|
|
223
|
+
response.status = 200
|
|
224
|
+
response['Content-type'] = 'text/html'
|
|
225
|
+
response.body = uploader_page
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
protected
|
|
229
|
+
|
|
230
|
+
##
|
|
231
|
+
# Finds a unique name in the same directory for the given file.
|
|
232
|
+
#
|
|
233
|
+
# The uploaded file will be renamed if a file by that name already exists.
|
|
234
|
+
# An index number is added to the file's base name to make it unique. For
|
|
235
|
+
# example if test.txt already existed then test_1.txt would be checked,
|
|
236
|
+
# followed by test_2.txt, and so on.
|
|
237
|
+
def unique_name(desired_name, save_directory)
|
|
238
|
+
ext = File.extname(desired_name)
|
|
239
|
+
base = File.basename(desired_name, ext)
|
|
240
|
+
|
|
241
|
+
final_base = full_base = File.join(save_directory, base)
|
|
242
|
+
i = 1
|
|
243
|
+
while(File.exist?(final_base + ext))
|
|
244
|
+
final_base = "#{full_base}_#{i}"
|
|
245
|
+
i += 1
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
final_base + ext
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
##
|
|
252
|
+
# Returns a string holding the full HTML page with the file upload form.
|
|
253
|
+
def uploader_page
|
|
254
|
+
html = [
|
|
255
|
+
"<h1>Uploader</h1>",
|
|
256
|
+
"<form action='' method='POST' enctype='multipart/form-data'>",
|
|
257
|
+
" <p>",
|
|
258
|
+
" Select file(s) to upload:",
|
|
259
|
+
" <br><br>",
|
|
260
|
+
" <input type='file' name='file' multiple='true'>",
|
|
261
|
+
" <br><br>",
|
|
262
|
+
" <input type='submit'>",
|
|
263
|
+
" </p>",
|
|
264
|
+
"</form>",
|
|
265
|
+
]
|
|
266
|
+
|
|
267
|
+
page(html, "Uploader")
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
##
|
|
271
|
+
# Returns a string holding the result of the upload page submission.
|
|
272
|
+
#
|
|
273
|
+
# +names+ is an array of the uploaded file names. These are names
|
|
274
|
+
# as submitted. Saved names may be different to avoid overwritting.
|
|
275
|
+
def uploaded_page(names)
|
|
276
|
+
html = [
|
|
277
|
+
"<h1>Results</h1>",
|
|
278
|
+
"<p>Uploaded:",
|
|
279
|
+
" <strong>#{names.join("</strong>, <strong>")}</strong>",
|
|
280
|
+
"</p>",
|
|
281
|
+
"<p><a href=''>Return to upload page</a></p>",
|
|
282
|
+
]
|
|
283
|
+
|
|
284
|
+
page(html, "Upload Results")
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
end
|
data/oddjob.gemspec
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path('./lib', File.dirname( __FILE__))
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
require 'oddjob/version'
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.name = 'oddjob'
|
|
9
|
+
spec.version = OddJob::VERSION
|
|
10
|
+
spec.authors = ['Mike Fellows']
|
|
11
|
+
spec.email = ['Mike.Fellows@shaw.ca']
|
|
12
|
+
|
|
13
|
+
spec.summary = 'OddJob is simple command line driven web server'
|
|
14
|
+
spec.description = <<TXT
|
|
15
|
+
Oddjob is a simple command line driver web server, written in ruby and
|
|
16
|
+
utilizing ruby's built in web server webrick. It is meant to be a test and
|
|
17
|
+
development tool, suitable for static content from a local directory.
|
|
18
|
+
|
|
19
|
+
Oddjob also provides basic file upload capabilities (single or multi-file
|
|
20
|
+
upload). This includes the ability to save uploaded files locally.
|
|
21
|
+
|
|
22
|
+
As a stand alone application the server is quick and convenient application
|
|
23
|
+
for web developers working with static files. Or get a copy of the source and
|
|
24
|
+
add in new endpoints for simple tests as needed.
|
|
25
|
+
TXT
|
|
26
|
+
|
|
27
|
+
spec.homepage = 'https://github.com/MCF/oddjob'
|
|
28
|
+
spec.license = 'MIT'
|
|
29
|
+
|
|
30
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
31
|
+
spec.bindir = 'bin'
|
|
32
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
33
|
+
spec.require_paths = ['lib']
|
|
34
|
+
spec.extra_rdoc_files = ['README.md', 'MIT-LICENSE']
|
|
35
|
+
spec.rdoc_options = ['--main', 'README.md']
|
|
36
|
+
|
|
37
|
+
spec.add_development_dependency('bundler', '~> 1.10')
|
|
38
|
+
spec.add_development_dependency('rake', '~> 10.0')
|
|
39
|
+
spec.add_development_dependency('rspec')
|
|
40
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: oddjob
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.6.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Mike Fellows
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-02-13 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.10'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.10'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rspec
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
description: |
|
|
56
|
+
Oddjob is a simple command line driver web server, written in ruby and
|
|
57
|
+
utilizing ruby's built in web server webrick. It is meant to be a test and
|
|
58
|
+
development tool, suitable for static content from a local directory.
|
|
59
|
+
|
|
60
|
+
Oddjob also provides basic file upload capabilities (single or multi-file
|
|
61
|
+
upload). This includes the ability to save uploaded files locally.
|
|
62
|
+
|
|
63
|
+
As a stand alone application the server is quick and convenient application
|
|
64
|
+
for web developers working with static files. Or get a copy of the source and
|
|
65
|
+
add in new endpoints for simple tests as needed.
|
|
66
|
+
email:
|
|
67
|
+
- Mike.Fellows@shaw.ca
|
|
68
|
+
executables:
|
|
69
|
+
- oddjob
|
|
70
|
+
extensions: []
|
|
71
|
+
extra_rdoc_files:
|
|
72
|
+
- README.md
|
|
73
|
+
- MIT-LICENSE
|
|
74
|
+
files:
|
|
75
|
+
- ".gitignore"
|
|
76
|
+
- Gemfile
|
|
77
|
+
- MIT-LICENSE
|
|
78
|
+
- README.md
|
|
79
|
+
- Rakefile
|
|
80
|
+
- bin/oddjob
|
|
81
|
+
- lib/oddjob.rb
|
|
82
|
+
- lib/oddjob/version.rb
|
|
83
|
+
- oddjob.gemspec
|
|
84
|
+
homepage: https://github.com/MCF/oddjob
|
|
85
|
+
licenses:
|
|
86
|
+
- MIT
|
|
87
|
+
metadata: {}
|
|
88
|
+
post_install_message:
|
|
89
|
+
rdoc_options:
|
|
90
|
+
- "--main"
|
|
91
|
+
- README.md
|
|
92
|
+
require_paths:
|
|
93
|
+
- lib
|
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
|
+
requirements:
|
|
96
|
+
- - ">="
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '0'
|
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
requirements: []
|
|
105
|
+
rubyforge_project:
|
|
106
|
+
rubygems_version: 2.4.5
|
|
107
|
+
signing_key:
|
|
108
|
+
specification_version: 4
|
|
109
|
+
summary: OddJob is simple command line driven web server
|
|
110
|
+
test_files: []
|