xmlrpc-scgi 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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +7 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +13 -0
- data/lib/xmlrpc/scgi.rb +122 -0
- data/lib/xmlrpc/scgi/version.rb +6 -0
- data/spec/client_spec.rb +27 -0
- data/spec/server_spec.rb +67 -0
- data/xmlrpc-scgi.gemspec +26 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 01932824af6cb128b102b0a984c5c4a2bd9637c4
|
4
|
+
data.tar.gz: 12462a5f89c3a5beab9e5ddc9de1cf79a0d656a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4b0cf638af945554445636afd32386fd82e622d703bdb1b0ca8eda345a64763771fb22c5c6335428be07b2ba6a18daa69313ac4dc043647abcae1a502db46d6f
|
7
|
+
data.tar.gz: 53bc728f0be1b82f5b39bf9745b54035069c8e9774b6a147f9522229d615a851051b1de44a30fbaaaebb2050fe0df3ea515444afde8f9921d317172a202a15b9
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 kannibalox
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# XMLRPC::SCGI
|
2
|
+
|
3
|
+
[](https://travis-ci.org/smuth4/ruby-xmlrpc-scgi)
|
4
|
+
|
5
|
+
A small gem to extend the XMLRPC module by adding an SCGI client and server. It also goes the extra mile and adds support for the non-standard `i8` tag.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'xmlrpc-scgi'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install scgi-xmlrpc
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Server
|
26
|
+
```ruby
|
27
|
+
require 'xmlrpc/scgi'
|
28
|
+
|
29
|
+
server = XMLRPC::SCGI.new '127.0.0.1:6000'
|
30
|
+
server.add_handler('add') do |a, b|
|
31
|
+
a + b
|
32
|
+
end
|
33
|
+
|
34
|
+
# Runs until it is killed
|
35
|
+
server.serve
|
36
|
+
```
|
37
|
+
|
38
|
+
Client
|
39
|
+
```ruby
|
40
|
+
require 'xmlrpc/scgi'
|
41
|
+
|
42
|
+
client = XMLRPC::SCGIClient.new '127.0.0.1', '', 6000
|
43
|
+
puts client.call('add', 4, 5)
|
44
|
+
```
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
1. Fork it ( https://github.com/[my-github-username]/scgi-xmlrpc/fork )
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
50
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
52
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/xmlrpc/scgi.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'xmlrpc/server'
|
3
|
+
require 'xmlrpc/client'
|
4
|
+
require 'xmlrpc/config'
|
5
|
+
|
6
|
+
require 'xmlrpc/scgi/version'
|
7
|
+
|
8
|
+
module XMLRPC
|
9
|
+
# A simple and naive server for serving XMLRPC over the SCGI protocol
|
10
|
+
class SCGIServer < XMLRPC::BasicServer
|
11
|
+
def initialize(socket, *a)
|
12
|
+
@socket = socket
|
13
|
+
super(*a)
|
14
|
+
end
|
15
|
+
|
16
|
+
def serve
|
17
|
+
if @socket.include? ':'
|
18
|
+
server = TCPServer.new(*@socket.split(':'))
|
19
|
+
else
|
20
|
+
server = UNIXServer.new(@socket)
|
21
|
+
end
|
22
|
+
loop do
|
23
|
+
begin
|
24
|
+
client = server.accept
|
25
|
+
_, body = split_request(client)
|
26
|
+
client.write write_http("\n#{process(body)}")
|
27
|
+
ensure
|
28
|
+
# no matter what we have to put this thread on the bad list
|
29
|
+
client.close unless client.nil? || client.closed?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_http(data)
|
35
|
+
content = [
|
36
|
+
'Status: 200 OK.',
|
37
|
+
'Content-Type: text/xml',
|
38
|
+
"Content-Length: #{data.length}",
|
39
|
+
data
|
40
|
+
]
|
41
|
+
content.join "\n\r"
|
42
|
+
end
|
43
|
+
|
44
|
+
def read_netstring(handle)
|
45
|
+
len = handle.gets(':', 10).sub(':', '')
|
46
|
+
payload = handle.read(len.to_i)
|
47
|
+
if handle.read(1) == ','
|
48
|
+
payload
|
49
|
+
else
|
50
|
+
fail "Malformed request, does not end with ','"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def write_netstring(str)
|
55
|
+
"#{str.length}:#{str},"
|
56
|
+
end
|
57
|
+
|
58
|
+
def split_request(socket)
|
59
|
+
return if socket.closed?
|
60
|
+
payload = read_netstring socket
|
61
|
+
request = Hash[*(payload.split("\0"))]
|
62
|
+
fail 'Missing CONTENT_LENGTH' unless request['CONTENT_LENGTH']
|
63
|
+
length = request['CONTENT_LENGTH'].to_i
|
64
|
+
body = length > 0 ? socket.read(length) : ''
|
65
|
+
[request, body]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# A small derivative class for calling XMLRPC over SCGI
|
70
|
+
class SCGIClient < XMLRPC::Client
|
71
|
+
def do_rpc(xml, _ = false)
|
72
|
+
headers = {
|
73
|
+
'CONTENT_LENGTH' => xml.size,
|
74
|
+
'SCGI' => 1
|
75
|
+
}
|
76
|
+
|
77
|
+
header = "#{headers.to_a.flatten.join("\x00")}"
|
78
|
+
request = "#{header.size}:#{header},#{xml}"
|
79
|
+
|
80
|
+
TCPSocket.open(@host, @port) do |s|
|
81
|
+
s.write(request)
|
82
|
+
s.read.split(/\n\s*?\n/, 2)[1]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module XMLRPC
|
89
|
+
module XMLParser
|
90
|
+
# Overriding the default XML parser
|
91
|
+
class AbstractStreamParser
|
92
|
+
# A patch for the response method as rtorrent xmlrpc
|
93
|
+
# call returns some integers as i8 instead of i4 expected
|
94
|
+
# this results in int8 fields showing up with no data
|
95
|
+
# as the parse method is not capable of handling such
|
96
|
+
# a tag.
|
97
|
+
|
98
|
+
alias_method 'original_parseMethodResponse', 'parseMethodResponse'
|
99
|
+
def parseMethodResponse(str) # rubocop:disable Style/MethodName
|
100
|
+
str.gsub!(%r{<((\/)*)i8>}, '<\1i4>')
|
101
|
+
original_parseMethodResponse(str)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
module XMLRPC
|
108
|
+
# Monkey patch the Create class
|
109
|
+
class Create
|
110
|
+
alias_method 'original_conv2value', 'conv2value'
|
111
|
+
|
112
|
+
def conv2value(param)
|
113
|
+
if ([Fixnum, Bignum].include? param.class) &&
|
114
|
+
(param <= -(2**31) || param >= (2**31 - 1))
|
115
|
+
cval = @writer.tag('i8', param.to_s)
|
116
|
+
@writer.ele('value', cval)
|
117
|
+
else
|
118
|
+
original_conv2value param
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'xmlrpc/scgi'
|
2
|
+
|
3
|
+
describe XMLRPC::SCGIClient do
|
4
|
+
before(:all) do
|
5
|
+
@server_thread = Thread.new do
|
6
|
+
server = XMLRPC::SCGIServer.new '127.0.0.1:6000'
|
7
|
+
server.add_handler('add') do |a, b|
|
8
|
+
a + b
|
9
|
+
end
|
10
|
+
server.serve
|
11
|
+
end
|
12
|
+
@client = XMLRPC::SCGIClient.new '127.0.0.1', '', 6000
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:all) do
|
16
|
+
Thread.kill @server_thread
|
17
|
+
@server_thread.join
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should perform calls' do
|
21
|
+
expect(@client.call('add', 4, 5)).to be(4 + 5)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should handle big ints calls' do
|
25
|
+
expect(@client.call('add', 2**(4 * 8), 5)).to be(2**(4 * 8) + 5)
|
26
|
+
end
|
27
|
+
end
|
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'xmlrpc/scgi'
|
2
|
+
|
3
|
+
describe XMLRPC::SCGIServer do
|
4
|
+
before(:each) do
|
5
|
+
@server = XMLRPC::SCGIServer.new 'fake socket'
|
6
|
+
end
|
7
|
+
|
8
|
+
context '.read_netstring' do
|
9
|
+
it 'Valid netstring' do
|
10
|
+
expect(@server.read_netstring(StringIO.new('5:hello,'))).to eql('hello')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'Invalid netstring - missing end comma' do
|
14
|
+
expect do
|
15
|
+
@server.read_netstring(StringIO.new('5:hello'))
|
16
|
+
end.to raise_error(RuntimeError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'Invalid netstring - invalid length' do
|
20
|
+
expect do
|
21
|
+
@server.read_netstring(StringIO.new('53457254754754:hello,'))
|
22
|
+
end.to raise_error(RuntimeError)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it '.write_netstring' do
|
27
|
+
expect(@server.write_netstring('hello')).to eql('5:hello,')
|
28
|
+
end
|
29
|
+
|
30
|
+
context '.split_request' do
|
31
|
+
before(:each) do
|
32
|
+
@request = [
|
33
|
+
'CONTENT_LENGTH',
|
34
|
+
'56',
|
35
|
+
'SCGI',
|
36
|
+
'1',
|
37
|
+
'REQUEST_METHOD',
|
38
|
+
'POST',
|
39
|
+
'REQUEST_URI',
|
40
|
+
'/deepthought'
|
41
|
+
]
|
42
|
+
|
43
|
+
@body = 'What is the answer to life, the Universe and everything?'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'Valid request' do
|
47
|
+
netstring = @server.write_netstring("#{@request.join("\0")}")
|
48
|
+
expect(@server.split_request(StringIO.new("#{netstring}#{@body}")))
|
49
|
+
.to eql([Hash[*@request], @body])
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'Invalid request - short body' do
|
53
|
+
netstring = @server.write_netstring("#{@request[0..-3].join("\0")}")
|
54
|
+
expect(@server.split_request(StringIO.new("#{netstring}#{@body}")))
|
55
|
+
.to_not eql([Hash[*@request], @body])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should spool up a server' do
|
60
|
+
server_thread = Thread.new do
|
61
|
+
server = XMLRPC::SCGIServer.new '127.0.0.1:6000'
|
62
|
+
server.serve
|
63
|
+
end
|
64
|
+
expect(server_thread.status).to be_a(String)
|
65
|
+
Thread.kill server_thread
|
66
|
+
end
|
67
|
+
end
|
data/xmlrpc-scgi.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'xmlrpc/scgi/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "xmlrpc-scgi"
|
8
|
+
spec.version = XMLRPC::SCGI::VERSION
|
9
|
+
spec.authors = ["Stephen Muth"]
|
10
|
+
spec.email = ["smuth4@gmail.com"]
|
11
|
+
spec.summary = %q{Extend XMLRPC with SCGI client and server.}
|
12
|
+
spec.description = %q{Extend XMLRPC with SCGI client and server.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
25
|
+
spec.add_development_dependency "rubocop", "~> 0.35"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xmlrpc-scgi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen Muth
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-04 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.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
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: '3.2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.35'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.35'
|
69
|
+
description: Extend XMLRPC with SCGI client and server.
|
70
|
+
email:
|
71
|
+
- smuth4@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".rubocop.yml"
|
78
|
+
- ".travis.yml"
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/xmlrpc/scgi.rb
|
84
|
+
- lib/xmlrpc/scgi/version.rb
|
85
|
+
- spec/client_spec.rb
|
86
|
+
- spec/server_spec.rb
|
87
|
+
- xmlrpc-scgi.gemspec
|
88
|
+
homepage: ''
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
metadata: {}
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 2.2.2
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Extend XMLRPC with SCGI client and server.
|
112
|
+
test_files:
|
113
|
+
- spec/client_spec.rb
|
114
|
+
- spec/server_spec.rb
|