riddl 0.125 → 0.126

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 260b0959b5e3cd03e5346a8e6002e6e7ab35ac81a90c099fabed18667b724f51
4
- data.tar.gz: 163523a732236a6e81fce5976437e2e7610f2a3fd171e2425b7eac36e7f6fe32
3
+ metadata.gz: 0eac3402149b89b4f1f94b4737e73be5c0f312951a70976703b8151a417e853e
4
+ data.tar.gz: 1d159b5d6baffd6f50b8dcf744c3f8e5fa8206bf47b346a2be9822e74228453a
5
5
  SHA512:
6
- metadata.gz: e6a4e14075147239fd64cf140c2d5feb563c2076ac7ffe2fd3d799ac7d66c58e44bcb3945a676a5e04d255e23c0c4a4bcd86283a88ae9292c3a3e938a1de0d45
7
- data.tar.gz: 89f7414265c9764de654494b43b736a234a62663abd01ec88ef1bf7e26dcbdb3a7a7c3399360c105930097ff08b21491f1acec58fd9aa0144e381856691dd4ee
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "riddl"
3
- s.version = "0.125"
3
+ s.version = "0.126"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.license = "LGPL-3.0"
6
6
  s.summary = "restful interface description and declaration language: tools and client/server libs"
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.125'
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-19 00:00:00.000000000 Z
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