riddl 1.0.15 → 1.0.16
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 +4 -4
- data/lib/ruby/riddl/protocols/generator.rb +150 -0
- data/lib/ruby/riddl/protocols/http/generator.rb +2 -1
- data/lib/ruby/riddl/protocols/parser.rb +208 -0
- data/riddl.gemspec +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e69bd3fbaa637fa772cb4be483543ea4add9a415688d76c39a01aa3cc627f31e
|
|
4
|
+
data.tar.gz: 9750596f66325159bc58d156cb1ff71e7fa6b862034d8bf6de25a5f3960a165d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 06f71177f1844c68b56a2c5a022882304f1932b5c21b961cf89dc1ff13f8c4338bc1c196d72e454035cbafd4acaaaaba4ddb41e0d9693dde0a9d8e1c8b090b1e
|
|
7
|
+
data.tar.gz: fd9102d88a796ccb51f4cb881dc7694d04570b4159c80c5e0a4f5e99b8294b999bc01ec6329e8bbfbd5565eb19e9d991f7b6a8042e3d4b18d3e301417f08bab5
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../constants')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../utils')
|
|
3
|
+
require 'stringio'
|
|
4
|
+
|
|
5
|
+
module Riddl
|
|
6
|
+
module Protocols
|
|
7
|
+
module HTTP
|
|
8
|
+
|
|
9
|
+
class StreamingBody
|
|
10
|
+
CHUNK_SIZE = 1 << 16 # 64 KiB
|
|
11
|
+
|
|
12
|
+
def initialize(parts)
|
|
13
|
+
@parts = parts
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def each
|
|
17
|
+
@parts.each do |part|
|
|
18
|
+
if part.respond_to?(:read)
|
|
19
|
+
part.rewind if part.respond_to?(:rewind)
|
|
20
|
+
while chunk = part.read(CHUNK_SIZE)
|
|
21
|
+
yield chunk
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
yield part.to_s
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def close
|
|
30
|
+
@parts.each do |part|
|
|
31
|
+
part.close if part.respond_to?(:close) && !part.is_a?(String)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class Generator
|
|
37
|
+
def initialize(params,headers)
|
|
38
|
+
@params = params
|
|
39
|
+
@headers = headers
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.merge(parts)
|
|
43
|
+
parts.map do |p|
|
|
44
|
+
if p.respond_to?(:read)
|
|
45
|
+
p.rewind if p.respond_to?(:rewind)
|
|
46
|
+
p.read
|
|
47
|
+
else
|
|
48
|
+
p.to_s
|
|
49
|
+
end
|
|
50
|
+
end.join
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def generate(mode=:output)
|
|
54
|
+
if @params.is_a?(Array) && @params.length == 1
|
|
55
|
+
body(@params[0],mode)
|
|
56
|
+
elsif @params.class == Riddl::Parameter::Simple || @params.class == Riddl::Parameter::Complex
|
|
57
|
+
body(@params,mode)
|
|
58
|
+
elsif @params.is_a?(Array) && @params.length > 1
|
|
59
|
+
multipart(mode)
|
|
60
|
+
else
|
|
61
|
+
if mode == :output
|
|
62
|
+
@headers['Content-Type'] = 'text/plain'
|
|
63
|
+
end
|
|
64
|
+
[]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def body(r,mode)
|
|
69
|
+
parts = []
|
|
70
|
+
case r
|
|
71
|
+
when Riddl::Parameter::Simple
|
|
72
|
+
if mode == :output
|
|
73
|
+
parts << r.value
|
|
74
|
+
@headers['Content-Type'] = 'text/plain'
|
|
75
|
+
@headers['Content-ID'] = r.name
|
|
76
|
+
@headers['RIDDL-TYPE'] = 'simple'
|
|
77
|
+
else
|
|
78
|
+
@headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
79
|
+
parts << Riddl::Protocols::Utils::escape(r.name) + '=' + Riddl::Protocols::Utils::escape(r.value)
|
|
80
|
+
end
|
|
81
|
+
when Riddl::Parameter::Complex
|
|
82
|
+
parts << r.value
|
|
83
|
+
@headers['Content-Type'] = r.mimetype + r.mimextra
|
|
84
|
+
@headers['RIDDL-TYPE'] = 'complex'
|
|
85
|
+
if r.filename.nil?
|
|
86
|
+
@headers['Content-ID'] = r.name
|
|
87
|
+
else
|
|
88
|
+
@headers['Content-Disposition'] = "riddl-data; name=\"#{r.name}\"; filename=\"#{r.filename}\""
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
parts
|
|
92
|
+
end
|
|
93
|
+
private :body
|
|
94
|
+
|
|
95
|
+
def multipart(mode)
|
|
96
|
+
parts = []
|
|
97
|
+
scount = ccount = 0
|
|
98
|
+
@params.each do |r|
|
|
99
|
+
case r
|
|
100
|
+
when Riddl::Parameter::Simple
|
|
101
|
+
scount += 1
|
|
102
|
+
when Riddl::Parameter::Complex
|
|
103
|
+
ccount += 1
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
if scount > 0 && ccount == 0
|
|
107
|
+
@headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
108
|
+
res = []
|
|
109
|
+
@params.each do |r|
|
|
110
|
+
case r
|
|
111
|
+
when Riddl::Parameter::Simple
|
|
112
|
+
res << Riddl::Protocols::Utils::escape(r.name) + '=' + Riddl::Protocols::Utils::escape(r.value)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
parts << res.join('&')
|
|
116
|
+
else
|
|
117
|
+
if scount + ccount > 0
|
|
118
|
+
@headers['Content-Type'] = "multipart/#{mode == :input ? 'form-data' : 'mixed'}; boundary=\"#{BOUNDARY}\""
|
|
119
|
+
@params.each do |r|
|
|
120
|
+
case r
|
|
121
|
+
when Riddl::Parameter::Simple
|
|
122
|
+
parts << '--' + BOUNDARY + EOL +
|
|
123
|
+
'RIDDL-TYPE: simple' + EOL +
|
|
124
|
+
"Content-Disposition: form-data; name=\"#{r.name}\"" + EOL +
|
|
125
|
+
EOL +
|
|
126
|
+
r.value.to_s +
|
|
127
|
+
EOL
|
|
128
|
+
when Riddl::Parameter::Complex
|
|
129
|
+
parts << '--' + BOUNDARY + EOL +
|
|
130
|
+
'RIDDL-TYPE: complex' + EOL +
|
|
131
|
+
"Content-Disposition: form-data; name=\"#{r.name}\"" +
|
|
132
|
+
(r.filename.nil? ? EOL : "; filename=\"#{r.filename}\"" + EOL) +
|
|
133
|
+
'Content-Transfer-Encoding: binary' + EOL +
|
|
134
|
+
'Content-Type: ' + r.mimetype + r.mimextra + EOL +
|
|
135
|
+
EOL
|
|
136
|
+
parts << r.value
|
|
137
|
+
parts << EOL
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
parts << '--' + BOUNDARY + '--' + EOL
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
parts
|
|
144
|
+
end
|
|
145
|
+
private :multipart
|
|
146
|
+
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../constants')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../parameter')
|
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../utils')
|
|
4
|
+
|
|
5
|
+
module Riddl
|
|
6
|
+
module Protocols
|
|
7
|
+
module HTTP
|
|
8
|
+
class Parser
|
|
9
|
+
MULTIPART_CONTENT_TYPES = [
|
|
10
|
+
#{{{
|
|
11
|
+
'multipart/form-data',
|
|
12
|
+
'multipart/related',
|
|
13
|
+
'multipart/mixed'
|
|
14
|
+
#}}}
|
|
15
|
+
].freeze
|
|
16
|
+
FORM_CONTENT_TYPES = [
|
|
17
|
+
#{{{
|
|
18
|
+
'application/x-www-form-urlencoded'
|
|
19
|
+
#}}}
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
def parse_content(input,ctype,content_length,content_disposition,content_id,riddl_type)
|
|
23
|
+
#{{{
|
|
24
|
+
ctype = nil if riddl_type == 'simple'
|
|
25
|
+
filename = content_disposition[/ filename="?([^\";]*)"?/ni, 1]
|
|
26
|
+
name = content_disposition[/ name="?([^\";]*)"?/ni, 1] || content_id
|
|
27
|
+
|
|
28
|
+
if ctype || filename
|
|
29
|
+
body = Parameter::Tempfile.new("RiddlMultipart")
|
|
30
|
+
body.binmode if body.respond_to?(:binmode)
|
|
31
|
+
else
|
|
32
|
+
body = ''
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if content_length == 0
|
|
36
|
+
# should never happen normally, but leave it in, as sombody might
|
|
37
|
+
# decide to use parse_content independently
|
|
38
|
+
bufsize = 16384
|
|
39
|
+
until input.eof?
|
|
40
|
+
c = input.read(bufsize)
|
|
41
|
+
raise EOFError, "bad content body" if c.nil? || c.empty?
|
|
42
|
+
body << c
|
|
43
|
+
content_length -= c.size
|
|
44
|
+
end
|
|
45
|
+
body << input.read
|
|
46
|
+
else
|
|
47
|
+
bufsize = 16384
|
|
48
|
+
until content_length <= 0
|
|
49
|
+
c = input.read(bufsize < content_length ? bufsize : content_length)
|
|
50
|
+
raise EOFError, "bad content body" if c.nil? || c.empty?
|
|
51
|
+
body << c
|
|
52
|
+
content_length -= c.size
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
body.rewind if body.respond_to?(:binmode)
|
|
56
|
+
|
|
57
|
+
if body.length > 0
|
|
58
|
+
add_to_params(name,body,filename,ctype,nil)
|
|
59
|
+
else
|
|
60
|
+
if body.respond_to?(:binmode)
|
|
61
|
+
body.close
|
|
62
|
+
body.unlink
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
#}}}
|
|
66
|
+
end
|
|
67
|
+
private :parse_content
|
|
68
|
+
|
|
69
|
+
def parse_multipart(input,content_type,content_length)
|
|
70
|
+
#{{{
|
|
71
|
+
content_type =~ %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
|
|
72
|
+
boundary = "--#{$1}"
|
|
73
|
+
|
|
74
|
+
boundary_size = boundary.size + EOL.size
|
|
75
|
+
content_length -= boundary_size
|
|
76
|
+
status = input.read(boundary_size)
|
|
77
|
+
raise EOFError, "bad content body" unless status == boundary + EOL
|
|
78
|
+
|
|
79
|
+
rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
|
|
80
|
+
|
|
81
|
+
buf = ""
|
|
82
|
+
bufsize = 16384
|
|
83
|
+
loop do
|
|
84
|
+
head = nil
|
|
85
|
+
body = ''
|
|
86
|
+
filename = ctype = name = nil
|
|
87
|
+
|
|
88
|
+
until head && buf =~ rx
|
|
89
|
+
if !head && i = buf.index(EOL+EOL)
|
|
90
|
+
head = buf.slice!(0, i+2) # First \r\n
|
|
91
|
+
buf.slice!(0, 2) # Second \r\n
|
|
92
|
+
|
|
93
|
+
filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
|
|
94
|
+
ctype = head[/Content-Type: (.*)#{EOL}/ni, 1]
|
|
95
|
+
name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
|
|
96
|
+
|
|
97
|
+
if ctype || filename
|
|
98
|
+
body = Parameter::Tempfile.new("RiddlMultipart")
|
|
99
|
+
body.binmode if body.respond_to?(:binmode)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
next
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Save the read body part.
|
|
106
|
+
if head && (boundary_size+4 < buf.size)
|
|
107
|
+
body << buf.slice!(0, buf.size - (boundary_size+4))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
c = input.read(bufsize < content_length ? bufsize : content_length)
|
|
111
|
+
raise EOFError, "bad content body" if c.nil? || c.empty?
|
|
112
|
+
content_length -= c.size
|
|
113
|
+
|
|
114
|
+
buf << c
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Save the rest.
|
|
118
|
+
if i = buf.index(rx)
|
|
119
|
+
body << buf.slice!(0, i)
|
|
120
|
+
buf.slice!(0, boundary_size+2)
|
|
121
|
+
content_length = -1 if $1 == "--"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
add_to_params(name,body,filename == '' ? nil : filename,ctype,head)
|
|
125
|
+
|
|
126
|
+
break if buf.empty? || content_length == -1
|
|
127
|
+
end
|
|
128
|
+
#}}}
|
|
129
|
+
end
|
|
130
|
+
private :parse_multipart
|
|
131
|
+
|
|
132
|
+
def add_to_params(name,body,filename,ctype,head)
|
|
133
|
+
#{{{
|
|
134
|
+
if filename == ""
|
|
135
|
+
# filename is blank which means no file has been selected
|
|
136
|
+
elsif filename && ctype
|
|
137
|
+
body.rewind
|
|
138
|
+
|
|
139
|
+
# Take the basename of the upload's original filename.
|
|
140
|
+
# This handles the full Windows paths given by Internet Explorer
|
|
141
|
+
# (and perhaps other broken user agents) without affecting
|
|
142
|
+
# those which give the lone filename.
|
|
143
|
+
filename =~ /^(?:.*[:\\\/])?(.*)/m
|
|
144
|
+
filename = $1
|
|
145
|
+
|
|
146
|
+
@params << Parameter::Complex.new(name, ctype, body, filename, head)
|
|
147
|
+
elsif !filename && ctype
|
|
148
|
+
body.rewind
|
|
149
|
+
|
|
150
|
+
# Generic multipart cases, not coming from a form
|
|
151
|
+
@params << Parameter::Complex.new(name, ctype, body, nil, head)
|
|
152
|
+
else
|
|
153
|
+
@params << Parameter::Simple.new(name, body, :body)
|
|
154
|
+
end
|
|
155
|
+
#}}}
|
|
156
|
+
end
|
|
157
|
+
private :add_to_params
|
|
158
|
+
|
|
159
|
+
def parse_nested_query(qs, type)
|
|
160
|
+
#{{{
|
|
161
|
+
(qs || '').split(/[#{D}] */n).each do |p|
|
|
162
|
+
k, v = Riddl::Protocols::Utils::unescape(p).split('=', 2)
|
|
163
|
+
@params << Parameter::Simple.new(k,v,type)
|
|
164
|
+
end
|
|
165
|
+
#}}}
|
|
166
|
+
end
|
|
167
|
+
private :parse_nested_query
|
|
168
|
+
|
|
169
|
+
def initialize(query_string,input,content_type,content_length,content_disposition,content_id,riddl_type)
|
|
170
|
+
#{{{
|
|
171
|
+
# rewind because in some cases it is not at start (when multipart without length)
|
|
172
|
+
|
|
173
|
+
begin
|
|
174
|
+
input.rewind if input.respond_to?(:rewind)
|
|
175
|
+
rescue Errno::ESPIPE
|
|
176
|
+
# Handles exceptions raised by input streams that cannot be rewound
|
|
177
|
+
# such as when using plain CGI under Apache
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# fixing for chunked
|
|
181
|
+
content_length = content_length && content_length.to_i > 0 ? content_length.to_i : input.size
|
|
182
|
+
|
|
183
|
+
media_type = content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase
|
|
184
|
+
@params = Riddl::Parameter::Array.new
|
|
185
|
+
parse_nested_query(query_string,:query)
|
|
186
|
+
if MULTIPART_CONTENT_TYPES.include?(media_type)
|
|
187
|
+
parse_multipart(input,content_type,content_length.to_i)
|
|
188
|
+
elsif FORM_CONTENT_TYPES.include?(media_type)
|
|
189
|
+
# sub is a fix for Safari Ajax postings that always append \0
|
|
190
|
+
parse_nested_query(input.read.sub(/\0\z/, ''),:body)
|
|
191
|
+
else
|
|
192
|
+
parse_content(input,content_type,content_length.to_i,content_disposition||'',content_id||'',riddl_type||'')
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
begin
|
|
196
|
+
input.rewind if input.respond_to?(:rewind)
|
|
197
|
+
rescue Errno::ESPIPE
|
|
198
|
+
# Handles exceptions raised by input streams that cannot be rewound
|
|
199
|
+
# such as when using plain CGI under Apache
|
|
200
|
+
end
|
|
201
|
+
#}}}
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
attr_reader :params
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
data/riddl.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: riddl
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Juergen 'eTM' Mangler
|
|
@@ -463,8 +463,10 @@ files:
|
|
|
463
463
|
- lib/ruby/riddl/ns/description/1.0/description.rng
|
|
464
464
|
- lib/ruby/riddl/option.rb
|
|
465
465
|
- lib/ruby/riddl/parameter.rb
|
|
466
|
+
- lib/ruby/riddl/protocols/generator.rb
|
|
466
467
|
- lib/ruby/riddl/protocols/http/generator.rb
|
|
467
468
|
- lib/ruby/riddl/protocols/http/parser.rb
|
|
469
|
+
- lib/ruby/riddl/protocols/parser.rb
|
|
468
470
|
- lib/ruby/riddl/protocols/sse.rb
|
|
469
471
|
- lib/ruby/riddl/protocols/utils.rb
|
|
470
472
|
- lib/ruby/riddl/protocols/websocket.rb
|
|
@@ -539,7 +541,7 @@ homepage: http://github.com/etm/riddl/
|
|
|
539
541
|
licenses:
|
|
540
542
|
- LGPL-3.0-or-later
|
|
541
543
|
metadata:
|
|
542
|
-
documentation_uri: https://gemdocs.org/gems/riddl/1.0.
|
|
544
|
+
documentation_uri: https://gemdocs.org/gems/riddl/1.0.16/
|
|
543
545
|
rdoc_options: []
|
|
544
546
|
require_paths:
|
|
545
547
|
- lib/ruby
|