safrano 0.0.8 → 0.0.9

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: 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