safrano 0.0.8 → 0.0.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd0dda1e8d7fc80e01fc15b50b0893a31b189bb95e0138c8c1e49f4d3cdb11d5
4
- data.tar.gz: 4155a3d6ca1dcd2817aab51bc85208ada311b8a120d4ed90e5a8fcd6c05d23b7
3
+ metadata.gz: 4af1e3f2a6c005cb7269a3eb1a0f3d9f4de7c46aa76a79323b2b4052599e41ed
4
+ data.tar.gz: c7293279d1b38862dd8c26e8e98c8f90ca3cf75f0111ef7bf7f5c3994a6d9d44
5
5
  SHA512:
6
- metadata.gz: e1b61fcb3776b7435821121eb41b21afcf5fba422cb7665182ca7dc4d5e11155c3ba92a41eee7c9dc20730728c838033aa4b30367fd0e518d108547b7fbb7bf5
7
- data.tar.gz: 270e6f1942254b239aed16b0bdb4ba8c5f48eba6fa676f9e9da9758e984c1cdd37a72cd355ed30326881013342538bf59b4de7b9143aabd2104d4c3fdf7faa0d
6
+ metadata.gz: ca004d2c4842f70b6032f0d4d3930d02df98f7d29dc661bba3e8fa4e54fd5b9617dd640fb1333be8af7e8a110f778956f7e62c0c42f64fe7dfdf65804793dc5d
7
+ data.tar.gz: '09cdef8944addc559a2b7231344dd25b216965e42ed4f0e4e71b7e400bcb6a23a0070a65d250897cf44e8a5b363b72174edb847ecd787204650ed873343f1db2'
data/lib/multipart.rb ADDED
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Simple multipart support for OData $batch purpose
4
+
5
+ module Multi
6
+ RETNL = "\r\n".freeze
7
+ HTTP_VERB_URI_REGEXP = /^(POST|GET|PUT|PATCH)\s+(\S*)\s?(\S*)$/.freeze
8
+ HEADER_REGEXP = %r{^([a-zA-Z\-]+):\s*([0-9a-zA-Z\-\/,\s]+;?\S*)\s*$}.freeze
9
+ module Parts
10
+ class Base
11
+ attr_accessor :parts
12
+ attr_reader :body
13
+ attr_reader :headers
14
+
15
+ def initialize(boundary)
16
+ @boundary = boundary
17
+ @headers = {}
18
+ @body = ''
19
+ @parts = []
20
+ end
21
+
22
+ def finalize
23
+ @parts.each do |part|
24
+ @body << "--#{@boundary}#{RETNL}"
25
+ @body << part.message_s
26
+ @body << RETNL
27
+ end
28
+ @body << "--#{@boundary}--#{RETNL}"
29
+ @headers['Content-Length'] = @body.bytesize.to_s
30
+ @body
31
+ end
32
+ end
33
+ class Mixed < Base
34
+ def initialize(boundary)
35
+ super(boundary)
36
+ @headers['Content-Type'] = "multipart/mixed;boundary=#{@boundary}"
37
+ end
38
+
39
+ def shadow_copy
40
+ self.class.new(@boundary)
41
+ end
42
+
43
+ def self.parse(inp, boundary)
44
+ @mmboundary = "--#{boundary}"
45
+ ret = Multi::Parts::Mixed.new(boundary)
46
+ inp.split(@mmboundary).each do |p|
47
+ ret.parts << parse_part(p) unless (p.strip == '--') || p.empty?
48
+ end
49
+ ret
50
+ end
51
+
52
+ # Ultrasimplified parser...
53
+ def self.parse_part(inp)
54
+ state = :start
55
+ ct_headers = {}
56
+ headers = {}
57
+ body_str = ''
58
+ http_method = nil
59
+ uri = nil
60
+ inp.each_line do |l|
61
+ next if l.strip.empty?
62
+
63
+ case state
64
+ when :start, :ohd
65
+ md = l.strip.match(HEADER_REGEXP)
66
+
67
+ if md
68
+ state = :ohd
69
+ ct_headers[md[1]] = md[2]
70
+ else
71
+ md = l.strip.match(HTTP_VERB_URI_REGEXP)
72
+ if md
73
+ state = :hd
74
+ http_method = md[1]
75
+ uri = md[2]
76
+ end
77
+ end
78
+ when :hd
79
+ md = l.strip.match(HEADER_REGEXP)
80
+ if md
81
+ state = :hd
82
+ headers[md[1]] = md[2]
83
+ else
84
+ body_str << l
85
+ state = :bd
86
+ end
87
+
88
+ when :bd
89
+ body_str << l
90
+ end
91
+ end
92
+ if ct_headers['Content-Type'] == 'application/http'
93
+
94
+ Multi::Part::HttpReq.new(headers,
95
+ http_method,
96
+ uri,
97
+ body_str)
98
+
99
+ else
100
+ # TODO: should probably be a BadRequestError ?
101
+ raise RuntimeError
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ module Part
108
+ class Base
109
+ attr_accessor :content_type
110
+ attr_accessor :content_transfer_enc
111
+ def initialize
112
+ @content = nil
113
+ end
114
+
115
+ attr_writer :content
116
+
117
+ def message_s
118
+ result = ''
119
+ result << "Content-Type: #{@content_type}#{RETNL}"
120
+ result << "Content-Transfer-Encoding: #{@content_transfer_enc}#{RETNL}"
121
+ result << RETNL
122
+ result << content.to_s
123
+ result
124
+ end
125
+ end
126
+
127
+ class HttpReq < Base
128
+ def initialize(headers, method, url, body)
129
+ super()
130
+ @content_type = 'application/http'
131
+ @content_transfer_enc = 'binary'
132
+ @headers = headers
133
+ @http_method = method
134
+ @url = url
135
+ @body = body
136
+ end
137
+
138
+ def finalize
139
+ @content = "#{@http_method} #{@url} HTTP/1.1#{RETNL}"
140
+ @headers.each do |k, v|
141
+ @content << "#{k}: #{v}#{RETNL}"
142
+ end
143
+ if @body != ''
144
+ @content << RETNL
145
+ @content << @body
146
+ end
147
+ @content
148
+ end
149
+
150
+ def content
151
+ @content = (@content || finalize)
152
+ end
153
+
154
+ # shamelessely copied from Rack::TEST:Session
155
+ def headers_for_env
156
+ converted_headers = {}
157
+
158
+ @headers.each do |name, value|
159
+ env_key = name.upcase.tr('-', '_')
160
+ env_key = 'HTTP_' + env_key unless env_key == 'CONTENT_TYPE'
161
+ converted_headers[env_key] = value
162
+ end
163
+
164
+ converted_headers
165
+ end
166
+
167
+ def batch_env
168
+ @env = ::Rack::MockRequest.env_for(@url,
169
+ method: @http_method,
170
+ input: @body_str)
171
+ @env.merge! headers_for_env
172
+ @env
173
+ end
174
+ end
175
+
176
+ class HttpGet < HttpReq
177
+ def initialize(url, app_headers)
178
+ super(app_headers, 'GET', url, '')
179
+ end
180
+ end
181
+ end
182
+ end
data/lib/odata/batch.rb CHANGED
@@ -2,66 +2,66 @@
2
2
 
3
3
  require 'rack_app.rb'
4
4
  require 'safrano_core.rb'
5
+ require 'webrick/httpstatus'
5
6
 
6
7
  module OData
7
- module Batch
8
- # Mayonaise
9
- class MyOApp < OData::ServerApp
10
- attr_writer :full_req
8
+ RETNEW = "\r\n".freeze
9
+ class Request
10
+ def create_batch_app
11
+ Batch::MyOApp.new(self)
12
+ end
11
13
 
12
- def batch_call(env)
13
- @request = OData::Request.new(env)
14
- @response = OData::Response.new
14
+ def parse_multipart_mixed
15
+ @boundary = media_type_params['boundary']
16
+ Multi::Parts::Mixed.parse(body.read, @boundary)
17
+ end
18
+ end
15
19
 
16
- dispatch
20
+ class Response
21
+ APPLICATION_HTTP_11 = ['Content-Type: application/http',
22
+ "Content-Transfer-Encoding: binary#{RETNEW}",
23
+ 'HTTP/1.1 '].join(RETNEW).freeze
24
+ StatusMessage = WEBrick::HTTPStatus::StatusMessage.freeze
25
+ def message_s
26
+ b = String.new(APPLICATION_HTTP_11)
27
+ b << "#{@status} #{StatusMessage[@status]} #{RETNEW}"
28
+ headers.each { |k, v| b << k.to_s << ':' << v.to_s << RETNEW }
29
+ b << RETNEW
30
+ b << @body[0].to_s
31
+ b << RETNEW
32
+ end
33
+ end
17
34
 
18
- @response.finish
19
- end
35
+ module Batch
36
+ # Mayonaise
37
+ class MyOApp < OData::ServerApp
38
+ attr_reader :full_req
39
+ attr_reader :response
20
40
 
21
- def batch_body
22
- b = ''
23
- @response.headers.each { |k, v| b << k.to_s << ':' << v.to_s << "\r\n" }
24
- b << "\r\n"
25
- b << @response.body[0].to_s
26
- b << "\r\n"
41
+ def initialize(full_req)
42
+ @full_req = full_req
27
43
  end
28
- end
29
44
 
30
- # Moutarde
31
- class RequestPartBuilder
32
- attr_accessor :body_str
33
- attr_accessor :odata_headers
34
- attr_accessor :headers
35
- attr_accessor :http_method
36
- attr_accessor :uri
37
- attr_accessor :env
38
- def initialize
39
- @headers = {}
40
- @odata_headers = {}
41
- @body_str = ''
45
+ # redefined for $batch
46
+ def before
47
+ headers 'Cache-Control' => 'no-cache'
48
+ @request.service = @full_req.service
49
+ headers 'DataServiceVersion' => @request.service.data_service_version
42
50
  end
43
51
 
44
- # shamelessely copied from Rack::TEST:Session
45
- def headers_for_env
46
- converted_headers = {}
52
+ def batch_call(part_req)
53
+ env = part_req.batch_env
54
+ env['HTTP_HOST'] = @full_req.env['HTTP_HOST']
47
55
 
48
- @headers.each do |name, value|
49
- env_key = name.upcase.tr('-', '_')
50
- env_key = 'HTTP_' + env_key unless env_key == 'CONTENT_TYPE'
51
- converted_headers[env_key] = value
52
- end
53
-
54
- converted_headers
55
- end
56
+ @request = OData::Request.new(env)
57
+ @response = OData::Response.new
56
58
 
57
- def batch_env
58
- @env = ::Rack::MockRequest.env_for(@uri,
59
- method: @http_method,
60
- input: @body_str)
61
- @env.merge! headers_for_env
62
- @env
59
+ before
60
+ dispatch
61
+ @response.finish
63
62
  end
64
63
  end
64
+
65
65
  # Huile d'olive extra
66
66
  class HandlerBase
67
67
  TREND = Safrano::Transition.new('', trans: 'transition_end')
@@ -85,8 +85,6 @@ module OData
85
85
  end
86
86
  # battre le tout
87
87
  class EnabledHandler < HandlerBase
88
- HTTP_VERB_URI_REGEXP = /^(POST|GET|PUT|PATCH)\s+(\S*)\s?(\S*)$/.freeze
89
- HEADER_REGEXP = %r{^([a-zA-Z\-]+):\s*([0-9a-zA-Z\-\/]+;?\S*)\s*$}.freeze
90
88
  attr_accessor :boundary
91
89
  attr_accessor :mmboundary
92
90
  attr_accessor :body_str
@@ -97,93 +95,28 @@ module OData
97
95
  @parts = []
98
96
  end
99
97
 
98
+ # here we are in the Batch handler object, and this POST should
99
+ # normally handle a $batch request
100
100
  def odata_post(req)
101
- odata_batch(req)
102
- end
103
-
104
- def odata_get(_req)
105
- [405, {}, 'You cant GET $batch, POST it ']
106
- end
107
-
108
- def odata_batch(req)
109
101
  @request = req
110
- if @request.media_type == 'multipart/mixed'
111
- read
112
- parse
113
- [202,
114
- { 'Content-Type' => "multipart/mixed;boundary=#{@boundary}" },
115
- process_parts]
116
- else
117
- [415, {}, 'Unsupported Media Type']
118
- end
119
- end
120
-
121
- def read
122
- @body_str = @request.body.read
123
- @boundary = @request.media_type_params['boundary']
124
- @mmboundary = '--' << @boundary
125
- end
126
102
 
127
- def parse
128
- body_str.split(@mmboundary).each do |p|
129
- @parts << parse_part(p) unless (p == '--\n') || p == '--' || p.empty?
130
- end
131
- end
103
+ if @request.media_type == 'multipart/mixed'
104
+ batcha = @request.create_batch_app
105
+ @mult_request = @request.parse_multipart_mixed
106
+ @mult_response = @mult_request.shadow_copy
132
107
 
133
- # Ultrasimplified parser...
134
- def parse_part(inp)
135
- state = :start
136
- part = RequestPartBuilder.new
137
- inp.each_line do |l|
138
- next if l.strip.empty?
139
-
140
- case state
141
- when :start, :ohd
142
- md = l.strip.match(HEADER_REGEXP)
143
-
144
- if md
145
- state = :ohd
146
- part.odata_headers[md[1]] = md[2]
147
- else
148
- md = l.strip.match(HTTP_VERB_URI_REGEXP)
149
- if md
150
- state = :hd
151
- part.http_method = md[1]
152
- part.uri = md[2]
153
- end
154
- end
155
- when :hd
156
- md = l.strip.match(HEADER_REGEXP)
157
- if md
158
- state = :hd
159
- part.headers[md[1]] = md[2]
160
- else
161
- part.body_str << l
162
- state = :bd
163
- end
164
-
165
- when :bd
166
- part.body_str << l
108
+ @mult_request.parts.each_with_object(@mult_response) do |req_part, mresp|
109
+ batcha.batch_call(req_part)
110
+ mresp.parts << batcha.response
167
111
  end
112
+ [202, @mult_response.headers, @mult_response.finalize]
113
+ else
114
+ [415, {}, 'Unsupported Media Type']
168
115
  end
169
- part
170
116
  end
171
117
 
172
- def process_parts
173
- full_batch_body = ''
174
- @parts.each do |p|
175
- next unless p.uri
176
-
177
- batcha = MyOApp.new
178
-
179
- batcha.full_req = @request
180
-
181
- batcha.batch_call(p.batch_env)
182
-
183
- full_batch_body << @mmboundary << "\r\n"
184
- full_batch_body << batcha.batch_body
185
- end
186
- full_batch_body << @mmboundary << "--\r\n"
118
+ def odata_get(_req)
119
+ [405, {}, 'You cant GET $batch, POST it ']
187
120
  end
188
121
  end
189
122
  end
@@ -4,8 +4,6 @@
4
4
  # Thus Below we have called that "EntityClass". It's meant as "Collection"
5
5
 
6
6
  require 'json'
7
- require 'pp'
8
- require 'pry'
9
7
  require 'rexml/document'
10
8
  require 'safrano_core.rb'
11
9
  require 'odata/error.rb'
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'pp'
4
3
  require 'odata/error.rb'
5
4
 
6
5
  # Ordering with ruby expression
data/lib/odata/entity.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'json'
2
- require 'pp'
3
2
  require 'rexml/document'
4
3
  require 'safrano.rb'
5
4
  require 'odata/collection.rb' # required for self.class.entity_type_name ??
data/lib/odata/error.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'json'
4
- require 'pp'
5
4
  require 'rexml/document'
6
5
  require 'safrano.rb'
7
6
 
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'set'
4
- require 'pp'
5
4
 
6
5
  # OData relation related classes/module
7
6
  module OData
data/lib/odata/walker.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'json'
4
- require 'pp'
5
4
  require 'rexml/document'
6
5
  require 'safrano.rb'
7
6
 
@@ -29,6 +28,8 @@ module OData
29
28
  attr_reader :do_links
30
29
 
31
30
  def initialize(service, path)
31
+ raise 'Walker is called with a nil service' unless service
32
+
32
33
  path = URI.decode_www_form_component(path)
33
34
  @context = service
34
35
  @contexts = [@context]
@@ -99,7 +100,6 @@ module OData
99
100
  else
100
101
  @context = nil
101
102
  @status = :error
102
- # @error = OData::ServerError
103
103
  @error = OData::ErrorNotFound
104
104
  end
105
105
 
data/lib/rack_app.rb CHANGED
@@ -4,7 +4,6 @@ require 'rack'
4
4
  require_relative 'odata/walker.rb'
5
5
  require_relative 'request.rb'
6
6
  require_relative 'response.rb'
7
- require 'pry'
8
7
 
9
8
  module OData
10
9
  # handle GET PUT etc
@@ -25,7 +24,14 @@ module OData
25
24
 
26
25
  def odata_error
27
26
  if @walker.error.nil?
28
- [500, {}, 'Server Error']
27
+
28
+ # this is too critical; raise a real Exception
29
+ # begin
30
+ raise 'Walker construction failed with a unknown Error '
31
+ # rescue StandardError
32
+ # binding.pry
33
+ # end
34
+ # [500, {}, 'Server Error']
29
35
  else
30
36
  @walker.error.odata_get(@request)
31
37
  end
@@ -82,7 +88,7 @@ module OData
82
88
 
83
89
  neg_error = @request.negotiate_service_version
84
90
 
85
- raise Error if neg_error
91
+ raise RuntimeError if neg_error
86
92
 
87
93
  return false unless @request.service
88
94
 
data/lib/safrano.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'json'
4
4
  require 'rexml/document'
5
+ require_relative './multipart.rb'
5
6
  require 'safrano_core.rb'
6
7
  require 'odata/entity.rb'
7
8
  require 'odata/attribute.rb'
data/lib/service.rb CHANGED
@@ -185,8 +185,8 @@ module OData
185
185
 
186
186
  def enable_batch
187
187
  @batch_handler = OData::Batch::EnabledHandler.new
188
- @v1.batch_handler = @batch_handler
189
- @v2.batch_handler = @batch_handler
188
+ (@v1.batch_handler = @batch_handler) if @v1
189
+ (@v2.batch_handler = @batch_handler) if @v2
190
190
  end
191
191
 
192
192
  def enable_v1_service
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safrano
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - D.M.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-27 00:00:00.000000000 Z
11
+ date: 2019-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: sequel
14
+ name: rack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.15'
19
+ version: '2.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '5.15'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rack
28
+ name: rack-cors
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.0'
33
+ version: '1.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.0'
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sequel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.15'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.15'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '12.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-test
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rubocop
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -72,6 +100,7 @@ executables: []
72
100
  extensions: []
73
101
  extra_rdoc_files: []
74
102
  files:
103
+ - lib/multipart.rb
75
104
  - lib/odata/attribute.rb
76
105
  - lib/odata/batch.rb
77
106
  - lib/odata/collection.rb