riddl 0.125 → 0.126
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ruby/riddl/protocols/generator.rb +118 -0
- data/lib/ruby/riddl/protocols/parser.rb +205 -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: 0eac3402149b89b4f1f94b4737e73be5c0f312951a70976703b8151a417e853e
|
4
|
+
data.tar.gz: 1d159b5d6baffd6f50b8dcf744c3f8e5fa8206bf47b346a2be9822e74228453a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e13489f6872f3d2c383c3c8a4dcf9a555f018aaee385ace34687e10043095129768c5a8c03fe849052777a5f613a1cd8c1a949313603ebfd39d8a97ed96f29f1
|
7
|
+
data.tar.gz: c4601e98d3c48e28749328467b0451d9b373dc7f46c96ee49f9ff02e6992661af79dc3689d293c13f09db3dc07ea7717b5bb1bd03186f08ffc8c3ae2ae360604
|
@@ -0,0 +1,118 @@
|
|
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
|
+
class Generator
|
9
|
+
def initialize(params,headers)
|
10
|
+
@params = params
|
11
|
+
@headers = headers
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate(mode=:output)
|
15
|
+
if @params.is_a?(Array) && @params.length == 1
|
16
|
+
body(@params[0],mode)
|
17
|
+
elsif @params.class == Riddl::Parameter::Simple || @params.class == Riddl::Parameter::Complex
|
18
|
+
body(@params,mode)
|
19
|
+
elsif @params.is_a?(Array) && @params.length > 1
|
20
|
+
multipart(mode)
|
21
|
+
else
|
22
|
+
if mode == :output
|
23
|
+
@headers['Content-Type'] = 'text/plain'
|
24
|
+
StringIO.new('','r+b')
|
25
|
+
else
|
26
|
+
StringIO.new('','r+b')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def body(r,mode)
|
32
|
+
tmp = StringIO.new('','r+b')
|
33
|
+
case r
|
34
|
+
when Riddl::Parameter::Simple
|
35
|
+
if mode == :output
|
36
|
+
tmp.write r.value
|
37
|
+
@headers['Content-Type'] = 'text/plain'
|
38
|
+
@headers['Content-ID'] = r.name
|
39
|
+
@headers['RIDDL-TYPE'] = 'simple'
|
40
|
+
end
|
41
|
+
if mode == :input
|
42
|
+
@headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
43
|
+
tmp.write Riddl::Protocols::Utils::escape(r.name) + '=' + Riddl::Protocols::Utils::escape(r.value)
|
44
|
+
end
|
45
|
+
when Riddl::Parameter::Complex
|
46
|
+
tmp.write(r.value.respond_to?(:read) ? r.value.read : r.value)
|
47
|
+
@headers['Content-Type'] = r.mimetype + r.mimextra
|
48
|
+
@headers['RIDDL-TYPE'] = 'complex'
|
49
|
+
if r.filename.nil?
|
50
|
+
@headers['Content-ID'] = r.name
|
51
|
+
else
|
52
|
+
@headers['Content-Disposition'] = "riddl-data; name=\"#{r.name}\"; filename=\"#{r.filename}\""
|
53
|
+
end
|
54
|
+
end
|
55
|
+
tmp.flush
|
56
|
+
tmp.rewind
|
57
|
+
tmp
|
58
|
+
end
|
59
|
+
private :body
|
60
|
+
|
61
|
+
def multipart(mode)
|
62
|
+
tmp = StringIO.new('','r+b')
|
63
|
+
scount = ccount = 0
|
64
|
+
@params.each do |r|
|
65
|
+
case r
|
66
|
+
when Riddl::Parameter::Simple
|
67
|
+
scount += 1
|
68
|
+
when Riddl::Parameter::Complex
|
69
|
+
ccount += 1
|
70
|
+
end
|
71
|
+
end
|
72
|
+
if scount > 0 && ccount == 0
|
73
|
+
@headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
74
|
+
res = []
|
75
|
+
@params.each do |r|
|
76
|
+
case r
|
77
|
+
when Riddl::Parameter::Simple
|
78
|
+
res << Riddl::Protocols::Utils::escape(r.name) + '=' + Riddl::Protocols::Utils::escape(r.value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
tmp.write res.join('&')
|
82
|
+
else
|
83
|
+
if scount + ccount > 0
|
84
|
+
@headers['Content-Type'] = "multipart/#{mode == :input ? 'form-data' : 'mixed'}; boundary=\"#{BOUNDARY}\""
|
85
|
+
@params.each do |r|
|
86
|
+
case r
|
87
|
+
when Riddl::Parameter::Simple
|
88
|
+
tmp.write '--' + BOUNDARY + EOL
|
89
|
+
tmp.write 'RIDDL-TYPE: simple' + EOL
|
90
|
+
tmp.write "Content-Disposition: #{mode == :input ? 'form-data' : 'riddl-data'}; name=\"#{r.name}\"" + EOL
|
91
|
+
tmp.write EOL
|
92
|
+
tmp.write r.value
|
93
|
+
tmp.write EOL
|
94
|
+
when Riddl::Parameter::Complex
|
95
|
+
tmp.write '--' + BOUNDARY + EOL
|
96
|
+
tmp.write 'RIDDL-TYPE: complex' + EOL
|
97
|
+
tmp.write "Content-Disposition: #{mode == :input ? 'form-data' : 'riddl-data'}; name=\"#{r.name}\""
|
98
|
+
tmp.write r.filename.nil? ? '; filename=""' + EOL : "; filename=\"#{r.filename}\"" + EOL
|
99
|
+
tmp.write 'Content-Transfer-Encoding: binary' + EOL
|
100
|
+
tmp.write 'Content-Type: ' + r.mimetype + r.mimextra + EOL
|
101
|
+
tmp.write EOL
|
102
|
+
tmp.write(r.value.respond_to?(:read) ? r.value.read : r.value)
|
103
|
+
tmp.write EOL
|
104
|
+
end
|
105
|
+
end
|
106
|
+
tmp.write '--' + BOUNDARY + EOL
|
107
|
+
end
|
108
|
+
end
|
109
|
+
tmp.flush
|
110
|
+
tmp.rewind
|
111
|
+
tmp
|
112
|
+
end
|
113
|
+
private :multipart
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,205 @@
|
|
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
|
+
# fixing for chunked?
|
25
|
+
|
26
|
+
ctype = nil if riddl_type == 'simple'
|
27
|
+
filename = content_disposition[/ filename="?([^\";]*)"?/ni, 1]
|
28
|
+
name = content_disposition[/ name="?([^\";]*)"?/ni, 1] || content_id
|
29
|
+
|
30
|
+
if ctype || filename
|
31
|
+
body = Parameter::Tempfile.new("RiddlMultipart")
|
32
|
+
body.binmode if body.respond_to?(:binmode)
|
33
|
+
else
|
34
|
+
body = ''
|
35
|
+
end
|
36
|
+
|
37
|
+
if content_length == 0
|
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
|
+
add_to_params(name,body,filename,ctype,nil) if body.length > 0
|
58
|
+
#}}}
|
59
|
+
end
|
60
|
+
private :parse_content
|
61
|
+
|
62
|
+
def parse_multipart(input,content_type,content_length)
|
63
|
+
#{{{
|
64
|
+
content_type =~ %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
|
65
|
+
boundary = "--#{$1}"
|
66
|
+
|
67
|
+
boundary_size = boundary.size + EOL.size
|
68
|
+
content_length -= boundary_size
|
69
|
+
status = input.read(boundary_size)
|
70
|
+
raise EOFError, "bad content body" unless status == boundary + EOL
|
71
|
+
|
72
|
+
rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
|
73
|
+
|
74
|
+
buf = ""
|
75
|
+
bufsize = 16384
|
76
|
+
loop do
|
77
|
+
head = nil
|
78
|
+
body = ''
|
79
|
+
filename = ctype = name = nil
|
80
|
+
|
81
|
+
until head && buf =~ rx
|
82
|
+
if !head && i = buf.index(EOL+EOL)
|
83
|
+
head = buf.slice!(0, i+2) # First \r\n
|
84
|
+
buf.slice!(0, 2) # Second \r\n
|
85
|
+
|
86
|
+
filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
|
87
|
+
ctype = head[/Content-Type: (.*)#{EOL}/ni, 1]
|
88
|
+
name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
|
89
|
+
|
90
|
+
if ctype || filename
|
91
|
+
body = Parameter::Tempfile.new("RiddlMultipart")
|
92
|
+
body.binmode if body.respond_to?(:binmode)
|
93
|
+
end
|
94
|
+
|
95
|
+
next
|
96
|
+
end
|
97
|
+
|
98
|
+
# Save the read body part.
|
99
|
+
if head && (boundary_size+4 < buf.size)
|
100
|
+
body << buf.slice!(0, buf.size - (boundary_size+4))
|
101
|
+
end
|
102
|
+
|
103
|
+
c = input.read(bufsize < content_length ? bufsize : content_length)
|
104
|
+
raise EOFError, "bad content body" if c.nil? || c.empty?
|
105
|
+
content_length -= c.size
|
106
|
+
|
107
|
+
buf << c
|
108
|
+
end
|
109
|
+
|
110
|
+
# Save the rest.
|
111
|
+
if i = buf.index(rx)
|
112
|
+
body << buf.slice!(0, i)
|
113
|
+
buf.slice!(0, boundary_size+2)
|
114
|
+
content_length = -1 if $1 == "--"
|
115
|
+
end
|
116
|
+
|
117
|
+
p name
|
118
|
+
p body
|
119
|
+
p filename
|
120
|
+
p ctype
|
121
|
+
p head
|
122
|
+
p '----'
|
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
|
+
media_type = content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase
|
181
|
+
@params = Riddl::Parameter::Array.new
|
182
|
+
parse_nested_query(query_string,:query)
|
183
|
+
if MULTIPART_CONTENT_TYPES.include?(media_type)
|
184
|
+
parse_multipart(input,content_type,content_length.to_i)
|
185
|
+
elsif FORM_CONTENT_TYPES.include?(media_type)
|
186
|
+
# sub is a fix for Safari Ajax postings that always append \0
|
187
|
+
parse_nested_query(input.read.sub(/\0\z/, ''),:body)
|
188
|
+
else
|
189
|
+
parse_content(input,content_type,content_length.to_i,content_disposition||'',content_id||'',riddl_type||'')
|
190
|
+
end
|
191
|
+
|
192
|
+
begin
|
193
|
+
input.rewind if input.respond_to?(:rewind)
|
194
|
+
rescue Errno::ESPIPE
|
195
|
+
# Handles exceptions raised by input streams that cannot be rewound
|
196
|
+
# such as when using plain CGI under Apache
|
197
|
+
end
|
198
|
+
#}}}
|
199
|
+
end
|
200
|
+
|
201
|
+
attr_reader :params
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
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: '0.
|
4
|
+
version: '0.126'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juergen 'eTM' Mangler
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: tools
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-02
|
13
|
+
date: 2023-03-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: daemonite
|
@@ -459,8 +459,10 @@ files:
|
|
459
459
|
- lib/ruby/riddl/ns/description/1.0/description.rng
|
460
460
|
- lib/ruby/riddl/option.rb
|
461
461
|
- lib/ruby/riddl/parameter.rb
|
462
|
+
- lib/ruby/riddl/protocols/generator.rb
|
462
463
|
- lib/ruby/riddl/protocols/http/generator.rb
|
463
464
|
- lib/ruby/riddl/protocols/http/parser.rb
|
465
|
+
- lib/ruby/riddl/protocols/parser.rb
|
464
466
|
- lib/ruby/riddl/protocols/sse.rb
|
465
467
|
- lib/ruby/riddl/protocols/utils.rb
|
466
468
|
- lib/ruby/riddl/protocols/websocket.rb
|