vcap_common 2.0.8 → 2.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/services/api.rb +0 -1
- data/lib/services/api/const.rb +0 -1
- data/lib/services/api/messages.rb +49 -6
- data/lib/vcap/component.rb +80 -18
- metadata +72 -26
- data/lib/services/api/clients/sds_client.rb +0 -84
- data/lib/services/api/multipart.rb +0 -191
data/lib/services/api.rb
CHANGED
data/lib/services/api/const.rb
CHANGED
@@ -26,7 +26,19 @@ module VCAP
|
|
26
26
|
optional :description, String
|
27
27
|
optional :info_url, URI::regexp(%w(http https))
|
28
28
|
optional :tags, [String]
|
29
|
+
optional :plan_details do
|
30
|
+
[
|
31
|
+
{
|
32
|
+
"name" => String,
|
33
|
+
"free" => bool,
|
34
|
+
optional("description") => String,
|
35
|
+
optional("extra") => String,
|
36
|
+
optional("unique_id") => String,
|
37
|
+
}
|
38
|
+
]
|
39
|
+
end
|
29
40
|
optional :plans, [String]
|
41
|
+
optional :plan_descriptions
|
30
42
|
optional :cf_plan_id
|
31
43
|
optional :plan_options
|
32
44
|
optional :binding_options
|
@@ -35,6 +47,8 @@ module VCAP
|
|
35
47
|
optional :timeout, Integer
|
36
48
|
optional :provider, String
|
37
49
|
optional :default_plan, String
|
50
|
+
optional :extra, String
|
51
|
+
optional :unique_id, String
|
38
52
|
end
|
39
53
|
|
40
54
|
class ProxiedServiceOfferingRequest < JsonMessage
|
@@ -49,6 +63,12 @@ module VCAP
|
|
49
63
|
required :credentials
|
50
64
|
end
|
51
65
|
|
66
|
+
class HandleUpdateRequestV2 < JsonMessage
|
67
|
+
required :token, String
|
68
|
+
required :gateway_data
|
69
|
+
required :credentials
|
70
|
+
end
|
71
|
+
|
52
72
|
class ListHandlesResponse < JsonMessage
|
53
73
|
required :handles, [Object]
|
54
74
|
end
|
@@ -72,12 +92,16 @@ module VCAP
|
|
72
92
|
end
|
73
93
|
|
74
94
|
class GatewayProvisionRequest < JsonMessage
|
75
|
-
required :
|
76
|
-
required :name,
|
77
|
-
required :
|
78
|
-
|
79
|
-
|
80
|
-
|
95
|
+
required :unique_id, String
|
96
|
+
required :name, String
|
97
|
+
required :email, String
|
98
|
+
|
99
|
+
optional :provider, String
|
100
|
+
optional :label, String
|
101
|
+
optional :plan, String
|
102
|
+
optional :version, String
|
103
|
+
optional :organization_guid, String
|
104
|
+
optional :space_guid, String
|
81
105
|
optional :plan_option
|
82
106
|
end
|
83
107
|
|
@@ -86,6 +110,7 @@ module VCAP
|
|
86
110
|
required :service_id, String
|
87
111
|
required :configuration
|
88
112
|
required :credentials
|
113
|
+
optional :dashboard_url, String
|
89
114
|
end
|
90
115
|
|
91
116
|
#
|
@@ -137,6 +162,24 @@ module VCAP
|
|
137
162
|
required :snapshots, [Object]
|
138
163
|
end
|
139
164
|
|
165
|
+
class CreateSnapshotV2Request < JsonMessage
|
166
|
+
required :name, /./
|
167
|
+
end
|
168
|
+
|
169
|
+
class SnapshotV2 < JsonMessage
|
170
|
+
required :snapshot_id, String
|
171
|
+
required :name, String
|
172
|
+
required :state, String
|
173
|
+
required :size, Integer
|
174
|
+
|
175
|
+
optional :created_time, String
|
176
|
+
optional :restored_time, String
|
177
|
+
end
|
178
|
+
|
179
|
+
class SnapshotListV2 < JsonMessage
|
180
|
+
required :snapshots, [Object]
|
181
|
+
end
|
182
|
+
|
140
183
|
class UpdateSnapshotNameRequest < JsonMessage
|
141
184
|
required :name, String
|
142
185
|
end
|
data/lib/vcap/component.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
+
require "base64"
|
2
3
|
require "eventmachine"
|
3
|
-
require
|
4
|
-
require "yajl"
|
4
|
+
require "monitor"
|
5
5
|
require "nats/client"
|
6
|
-
require "
|
7
|
-
require
|
6
|
+
require "set"
|
7
|
+
require "thin"
|
8
|
+
require "yajl"
|
9
|
+
require "vmstat"
|
8
10
|
|
9
11
|
module VCAP
|
10
12
|
|
@@ -48,34 +50,85 @@ module VCAP
|
|
48
50
|
CONFIG_SUPPRESS = Set.new([:mbus, :service_mbus, :keys, :database_environment, :password, :pass, :token])
|
49
51
|
|
50
52
|
class << self
|
53
|
+
class SafeHash < BasicObject
|
54
|
+
def initialize(hash = {})
|
55
|
+
@hash = hash
|
56
|
+
end
|
57
|
+
|
58
|
+
def threadsafe!
|
59
|
+
@monitor = ::Monitor.new
|
60
|
+
end
|
61
|
+
|
62
|
+
def synchronize
|
63
|
+
if @monitor
|
64
|
+
@monitor.synchronize do
|
65
|
+
begin
|
66
|
+
@thread = ::Thread.current
|
67
|
+
yield
|
68
|
+
ensure
|
69
|
+
@thread = nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
else
|
73
|
+
yield
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing(sym, *args, &blk)
|
78
|
+
if @monitor && @thread != ::Thread.current
|
79
|
+
::Kernel.raise "Lock required"
|
80
|
+
end
|
81
|
+
|
82
|
+
@hash.__send__(sym, *args, &blk)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def varz
|
87
|
+
@varz ||= SafeHash.new
|
88
|
+
end
|
51
89
|
|
52
|
-
attr_reader :varz
|
53
90
|
attr_accessor :healthz
|
54
91
|
|
55
92
|
def updated_varz
|
56
93
|
@last_varz_update ||= 0
|
57
|
-
if Time.now.to_f - @last_varz_update >= 1
|
58
|
-
# Snapshot uptime
|
59
|
-
@varz[:uptime] = VCAP.uptime_string(Time.now - @varz[:start])
|
60
94
|
|
61
|
-
|
95
|
+
if Time.now.to_f - @last_varz_update >= 1
|
96
|
+
# Grab current cpu and memory usage
|
62
97
|
rss, pcpu = `ps -o rss=,pcpu= -p #{Process.pid}`.split
|
63
|
-
@varz[:mem] = rss.to_i
|
64
|
-
@varz[:cpu] = pcpu.to_f
|
65
98
|
|
66
|
-
|
99
|
+
# Update varz
|
100
|
+
varz.synchronize do
|
101
|
+
@last_varz_update = Time.now.to_f
|
102
|
+
|
103
|
+
varz[:uptime] = VCAP.uptime_string(Time.now - varz[:start])
|
104
|
+
varz[:mem] = rss.to_i
|
105
|
+
varz[:cpu] = pcpu.to_f
|
106
|
+
|
107
|
+
memory = Vmstat.memory
|
108
|
+
varz[:mem_used_bytes] = memory.active_bytes + memory.wired_bytes
|
109
|
+
varz[:mem_free_bytes] = memory.inactive_bytes + memory.free_bytes
|
110
|
+
|
111
|
+
varz[:cpu_load_avg] = Vmstat.load_average.one_minute
|
112
|
+
|
113
|
+
# Return duplicate while holding lock
|
114
|
+
return varz.dup
|
115
|
+
end
|
116
|
+
else
|
117
|
+
# Return duplicate while holding lock
|
118
|
+
varz.synchronize do
|
119
|
+
return varz.dup
|
120
|
+
end
|
67
121
|
end
|
68
|
-
varz
|
69
122
|
end
|
70
123
|
|
71
124
|
def updated_healthz
|
72
125
|
@last_healthz_update ||= 0
|
126
|
+
|
73
127
|
if Time.now.to_f - @last_healthz_update >= 1
|
74
|
-
# ...
|
75
128
|
@last_healthz_update = Time.now.to_f
|
76
129
|
end
|
77
130
|
|
78
|
-
healthz
|
131
|
+
healthz.dup
|
79
132
|
end
|
80
133
|
|
81
134
|
def start_http_server(host, port, auth, logger)
|
@@ -98,6 +151,9 @@ module VCAP
|
|
98
151
|
@discover[:uuid]
|
99
152
|
end
|
100
153
|
|
154
|
+
# Announces the availability of this component to NATS.
|
155
|
+
# Returns the published configuration of the component,
|
156
|
+
# including the ephemeral port and credentials.
|
101
157
|
def register(opts)
|
102
158
|
uuid = VCAP.secure_uuid
|
103
159
|
type = opts[:type]
|
@@ -108,6 +164,7 @@ module VCAP
|
|
108
164
|
nats = opts[:nats] || NATS
|
109
165
|
auth = [opts[:user] || VCAP.secure_uuid, opts[:password] || VCAP.secure_uuid]
|
110
166
|
logger = opts[:logger] || Logger.new(nil)
|
167
|
+
log_counter = opts[:log_counter]
|
111
168
|
|
112
169
|
# Discover message limited
|
113
170
|
@discover = {
|
@@ -120,9 +177,12 @@ module VCAP
|
|
120
177
|
}
|
121
178
|
|
122
179
|
# Varz is customizable
|
123
|
-
|
124
|
-
|
125
|
-
|
180
|
+
varz.synchronize do
|
181
|
+
varz.merge!(@discover.dup)
|
182
|
+
varz[:num_cores] = VCAP.num_cores
|
183
|
+
varz[:config] = sanitize_config(opts[:config]) if opts[:config]
|
184
|
+
varz[:log_counter] = log_counter if log_counter
|
185
|
+
end
|
126
186
|
|
127
187
|
@healthz = "ok\n".freeze
|
128
188
|
|
@@ -140,6 +200,8 @@ module VCAP
|
|
140
200
|
|
141
201
|
# Also announce ourselves on startup..
|
142
202
|
nats.publish('vcap.component.announce', @discover.to_json)
|
203
|
+
|
204
|
+
@discover
|
143
205
|
end
|
144
206
|
|
145
207
|
def update_discover_uptime
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vcap_common
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
@@ -130,7 +130,7 @@ dependencies:
|
|
130
130
|
requirements:
|
131
131
|
- - ~>
|
132
132
|
- !ruby/object:Gem::Version
|
133
|
-
version: 1.0
|
133
|
+
version: '1.0'
|
134
134
|
type: :runtime
|
135
135
|
prerelease: false
|
136
136
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -138,7 +138,7 @@ dependencies:
|
|
138
138
|
requirements:
|
139
139
|
- - ~>
|
140
140
|
- !ruby/object:Gem::Version
|
141
|
-
version: 1.0
|
141
|
+
version: '1.0'
|
142
142
|
- !ruby/object:Gem::Dependency
|
143
143
|
name: multipart-post
|
144
144
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,6 +171,22 @@ dependencies:
|
|
171
171
|
- - ! '>='
|
172
172
|
- !ruby/object:Gem::Version
|
173
173
|
version: '0'
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: vmstat
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ~>
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '2.0'
|
182
|
+
type: :runtime
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ~>
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '2.0'
|
174
190
|
- !ruby/object:Gem::Dependency
|
175
191
|
name: rake
|
176
192
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,6 +203,38 @@ dependencies:
|
|
187
203
|
- - ~>
|
188
204
|
- !ruby/object:Gem::Version
|
189
205
|
version: 0.9.2
|
206
|
+
- !ruby/object:Gem::Dependency
|
207
|
+
name: rspec
|
208
|
+
requirement: !ruby/object:Gem::Requirement
|
209
|
+
none: false
|
210
|
+
requirements:
|
211
|
+
- - ! '>='
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '0'
|
214
|
+
type: :development
|
215
|
+
prerelease: false
|
216
|
+
version_requirements: !ruby/object:Gem::Requirement
|
217
|
+
none: false
|
218
|
+
requirements:
|
219
|
+
- - ! '>='
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0'
|
222
|
+
- !ruby/object:Gem::Dependency
|
223
|
+
name: sinatra
|
224
|
+
requirement: !ruby/object:Gem::Requirement
|
225
|
+
none: false
|
226
|
+
requirements:
|
227
|
+
- - ! '>='
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
none: false
|
234
|
+
requirements:
|
235
|
+
- - ! '>='
|
236
|
+
- !ruby/object:Gem::Version
|
237
|
+
version: '0'
|
190
238
|
description: common vcap classes/methods
|
191
239
|
email:
|
192
240
|
- derek.collison@gmail.com
|
@@ -194,32 +242,30 @@ executables: []
|
|
194
242
|
extensions: []
|
195
243
|
extra_rdoc_files: []
|
196
244
|
files:
|
197
|
-
- lib/
|
198
|
-
- lib/
|
199
|
-
- lib/
|
200
|
-
- lib/
|
201
|
-
- lib/
|
202
|
-
- lib/
|
203
|
-
- lib/
|
204
|
-
- lib/vcap/spec/forked_component/nats_server.rb
|
205
|
-
- lib/vcap/priority_queue.rb
|
245
|
+
- lib/json_message.rb
|
246
|
+
- lib/services/api/async_requests.rb
|
247
|
+
- lib/services/api/clients/service_gateway_client.rb
|
248
|
+
- lib/services/api/const.rb
|
249
|
+
- lib/services/api/messages.rb
|
250
|
+
- lib/services/api/util.rb
|
251
|
+
- lib/services/api.rb
|
206
252
|
- lib/vcap/common.rb
|
253
|
+
- lib/vcap/component.rb
|
254
|
+
- lib/vcap/config.rb
|
207
255
|
- lib/vcap/fiber_tracing.rb
|
208
|
-
- lib/vcap/
|
209
|
-
- lib/vcap/quota.rb
|
256
|
+
- lib/vcap/priority_queue.rb
|
210
257
|
- lib/vcap/process_utils.rb
|
258
|
+
- lib/vcap/quota.rb
|
211
259
|
- lib/vcap/rolling_metric.rb
|
212
|
-
- lib/vcap/config.rb
|
213
260
|
- lib/vcap/sorted_set_utils.rb
|
214
|
-
- lib/
|
215
|
-
- lib/
|
216
|
-
- lib/
|
217
|
-
- lib/
|
218
|
-
- lib/
|
219
|
-
- lib/
|
220
|
-
- lib/
|
221
|
-
- lib/
|
222
|
-
- lib/services/api/clients/service_gateway_client.rb
|
261
|
+
- lib/vcap/spec/em.rb
|
262
|
+
- lib/vcap/spec/forked_component/base.rb
|
263
|
+
- lib/vcap/spec/forked_component/nats_server.rb
|
264
|
+
- lib/vcap/spec/forked_component.rb
|
265
|
+
- lib/vcap/subprocess.rb
|
266
|
+
- lib/vcap/user_pools/user_ops.rb
|
267
|
+
- lib/vcap/user_pools/user_pool.rb
|
268
|
+
- lib/vcap/user_pools/user_pool_util.rb
|
223
269
|
homepage: http://github.com/vmware-ac/core
|
224
270
|
licenses: []
|
225
271
|
post_install_message:
|
@@ -240,7 +286,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
240
286
|
version: '0'
|
241
287
|
requirements: []
|
242
288
|
rubyforge_project:
|
243
|
-
rubygems_version: 1.8.
|
289
|
+
rubygems_version: 1.8.23
|
244
290
|
signing_key:
|
245
291
|
specification_version: 3
|
246
292
|
summary: vcap common
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
-
require 'net/http'
|
3
|
-
require 'net/http/post/multipart'
|
4
|
-
require 'mime/types'
|
5
|
-
require 'uri'
|
6
|
-
|
7
|
-
require 'services/api/const'
|
8
|
-
require 'services/api/messages'
|
9
|
-
require 'services/api/multipart'
|
10
|
-
|
11
|
-
module VCAP
|
12
|
-
module Services
|
13
|
-
module Api
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
module VCAP::Services::Api
|
19
|
-
class SDSClient
|
20
|
-
|
21
|
-
class SDSErrorResponse < StandardError; end
|
22
|
-
class UnexpectedResponse < StandardError; end
|
23
|
-
|
24
|
-
def initialize(url, upload_token, timeout=60, opts={})
|
25
|
-
@url = url
|
26
|
-
@timeout = timeout
|
27
|
-
@hdrs = {
|
28
|
-
'Content-Type' => 'application/json',
|
29
|
-
}
|
30
|
-
@upload_hdrs = {
|
31
|
-
'Content-Type' => 'multipart/form-data',
|
32
|
-
SDS_UPLOAD_TOKEN_HEADER => upload_token
|
33
|
-
}
|
34
|
-
end
|
35
|
-
|
36
|
-
def import_from_data(args)
|
37
|
-
resp = perform_multipart_upload("/serialized/#{args[:service]}/#{args[:service_id]}/serialized/data", args[:msg])
|
38
|
-
SerializedURL.decode(resp)
|
39
|
-
end
|
40
|
-
|
41
|
-
protected
|
42
|
-
|
43
|
-
def perform_multipart_upload(path, file_path)
|
44
|
-
# upload file using multipart/form data
|
45
|
-
result = nil
|
46
|
-
uri = URI.parse(@url)
|
47
|
-
|
48
|
-
mime_types = MIME::Types.type_for(file_path) || []
|
49
|
-
mime_types << "application/octet-stream" if mime_types.empty?
|
50
|
-
|
51
|
-
if EM.reactor_running?
|
52
|
-
payload = {:_method => 'put', :data_file => EM::StreamUploadIO.new(file_path, mime_types[0])}
|
53
|
-
multipart = EM::Multipart.new(payload, @upload_hdrs)
|
54
|
-
url = URI.parse(uri.to_s + path)
|
55
|
-
http = AsyncHttpMultiPartUpload.fibered(url, @timeout, multipart)
|
56
|
-
raise UnexpectedResponse, "Error uploading #{file_path} to serialized_data_server #{@url}: #{http.error}" unless http.error.empty?
|
57
|
-
code = http.response_header.status.to_i
|
58
|
-
body = http.response
|
59
|
-
else
|
60
|
-
payload = {:_method => 'put', :data_file => UploadIO.new(file_path, mime_types[0])}
|
61
|
-
req = Net::HTTP::Post::Multipart.new(path, payload, @upload_hdrs)
|
62
|
-
resp = Net::HTTP.new(uri.host, uri.port).start do |http|
|
63
|
-
http.request(req)
|
64
|
-
end
|
65
|
-
code = resp.code.to_i
|
66
|
-
body = resp.body
|
67
|
-
end
|
68
|
-
case code
|
69
|
-
when 200
|
70
|
-
body
|
71
|
-
when 400
|
72
|
-
raise SDSErrorResponse, "Fail to upload the file to serialization_data_server."
|
73
|
-
when 403
|
74
|
-
raise SDSErrorResponse, "You are forbidden to access serialization_data_server."
|
75
|
-
when 404
|
76
|
-
raise SDSErrorResponse, "Not found in serialization_data_server."
|
77
|
-
when 501
|
78
|
-
raise SDSErrorResponse, "Serialized data file is recognized, but file not found in serialization_data_server."
|
79
|
-
else
|
80
|
-
raise UnexpectedResponse, "Unexpected exception in serialization_data_server: #{(uri.to_s + path)} #{code} #{body}"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,191 +0,0 @@
|
|
1
|
-
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
-
require 'eventmachine'
|
3
|
-
require 'em-http-request'
|
4
|
-
|
5
|
-
# monkey-patch for em-http-request to support multipart file upload
|
6
|
-
|
7
|
-
module EventMachine
|
8
|
-
class StreamUploadIO
|
9
|
-
attr_reader :args, :filename, :basename, :size, :content_type
|
10
|
-
def initialize(filename, content_type, args={})
|
11
|
-
# disable http chunking
|
12
|
-
@args = args.merge({:http_chunks => false})
|
13
|
-
@filename = filename
|
14
|
-
# FIXME how to catch exception and log it
|
15
|
-
begin
|
16
|
-
@basename = File.basename(filename)
|
17
|
-
@size = File.size(filename)
|
18
|
-
rescue => e
|
19
|
-
# size == 0, the part will be injected
|
20
|
-
@size = 0
|
21
|
-
end
|
22
|
-
@content_type = content_type
|
23
|
-
end
|
24
|
-
|
25
|
-
def add_extra_size(extra_size)
|
26
|
-
@size += extra_size
|
27
|
-
end
|
28
|
-
|
29
|
-
def length
|
30
|
-
@size
|
31
|
-
end
|
32
|
-
|
33
|
-
def stream_file_data
|
34
|
-
true
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
module Part
|
39
|
-
def self.create(boundary, k, v)
|
40
|
-
if v.respond_to?(:stream_file_data)
|
41
|
-
FilePart.new(boundary, k, v)
|
42
|
-
else
|
43
|
-
ParamPart.new(boundary, k, v)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def to_io
|
48
|
-
@io
|
49
|
-
end
|
50
|
-
|
51
|
-
def length
|
52
|
-
@io.size
|
53
|
-
end
|
54
|
-
|
55
|
-
def send_part(conn, parts, idx)
|
56
|
-
end
|
57
|
-
|
58
|
-
def get_next_part(parts, idx)
|
59
|
-
next_idx = idx.to_i + 1
|
60
|
-
if parts && next_idx < parts.size && next_idx >=0
|
61
|
-
next_part = parts[next_idx]
|
62
|
-
else
|
63
|
-
nil
|
64
|
-
end
|
65
|
-
next_part
|
66
|
-
end
|
67
|
-
|
68
|
-
def send_next_part(conn, parts, idx)
|
69
|
-
next_part = get_next_part(parts, idx)
|
70
|
-
next_part.send_part(conn, parts, idx+1) if next_part
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
class ParamPart
|
76
|
-
include Part
|
77
|
-
def initialize(boundary, name, value)
|
78
|
-
@boundary = boundary
|
79
|
-
@name = name
|
80
|
-
part = ''
|
81
|
-
part << "--#{@boundary}\r\n"
|
82
|
-
part << "Content-Disposition: form-data; name=\"#{@name.to_s}\"\r\n"
|
83
|
-
part << "\r\n"
|
84
|
-
part << "#{value.to_s}\r\n"
|
85
|
-
@io = StringIO.new(part)
|
86
|
-
end
|
87
|
-
|
88
|
-
def send_part(conn, parts, idx)
|
89
|
-
conn.send_data @io.string if conn
|
90
|
-
send_next_part(conn, parts, idx)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
class EpiloguePart
|
95
|
-
include Part
|
96
|
-
def initialize(boundary)
|
97
|
-
@io = StringIO.new("--#{boundary}--\r\n") #\r\n or \r\n\r\n
|
98
|
-
end
|
99
|
-
|
100
|
-
def send_part(conn, parts, idx)
|
101
|
-
conn.send_data @io.string if conn
|
102
|
-
# this part should be the last part
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
class FilePart
|
107
|
-
include Part
|
108
|
-
def initialize(boundary, name, upload_io)
|
109
|
-
@boundary = boundary
|
110
|
-
@name = name
|
111
|
-
@io = upload_io
|
112
|
-
@part = ''
|
113
|
-
@part << "--#{boundary}\r\n"
|
114
|
-
@part << "Content-Disposition: form-data; name=\"#{name.to_s}\"; filename=\"#{@io.filename}\"\r\n"
|
115
|
-
@part << "Content-Length: #{@io.size}\r\n"
|
116
|
-
@part << "Content-Type: #{@io.content_type}\r\n"
|
117
|
-
@part << "Content-Transfer-Encoding: binary\r\n"
|
118
|
-
@part << "\r\n"
|
119
|
-
@end_part ="\r\n"
|
120
|
-
@io.add_extra_size(@part.size + @end_part.size)
|
121
|
-
end
|
122
|
-
|
123
|
-
def send_part(conn, parts, idx)
|
124
|
-
conn.send_data @part
|
125
|
-
streamer = EM::FileStreamer.new(conn, @io.filename, @io.args)
|
126
|
-
streamer.callback {
|
127
|
-
conn.send_data @end_part
|
128
|
-
send_next_part(conn, parts, idx)
|
129
|
-
}
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
class Multipart
|
134
|
-
DEFAULT_BOUNDARY = "-----------RubyEMMultiPartPost"
|
135
|
-
attr_reader :parts, :ps, :content_type, :content_length, :boundary, :headers
|
136
|
-
def initialize(params, headers={}, boundary=DEFAULT_BOUNDARY)
|
137
|
-
@parts = params.map{ |k,v| Part.create(boundary, k, v) }
|
138
|
-
@parts << EpiloguePart.new(boundary)
|
139
|
-
# inject the part with length = 0
|
140
|
-
@ps = @parts.select{ |part| part.length > 0 }
|
141
|
-
@content_type = "multipart/form-data; boundary=#{boundary}"
|
142
|
-
@content_length = 0
|
143
|
-
@parts.each do |part|
|
144
|
-
@content_length += part.length
|
145
|
-
end
|
146
|
-
@boundary = boundary
|
147
|
-
@headers = headers
|
148
|
-
end
|
149
|
-
|
150
|
-
def send_body(conn)
|
151
|
-
if conn && conn.error.nil? && @parts.size > 0
|
152
|
-
part = @parts.first
|
153
|
-
part.send_part(conn, @parts, 0)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
## Support to streaming the file when sending body
|
160
|
-
## TODO FIXME this patch whether depends on specified version???
|
161
|
-
module EventMachine
|
162
|
-
class HttpClient
|
163
|
-
alias_method :original_send_request, :send_request
|
164
|
-
def multipart_request?
|
165
|
-
(@req.method == 'POST' or @req.method == 'PUT') and @options[:multipart]
|
166
|
-
end
|
167
|
-
|
168
|
-
def send_request(head, body)
|
169
|
-
unless multipart_request?
|
170
|
-
original_send_request(head, body)
|
171
|
-
else
|
172
|
-
body = normalize_body(body)
|
173
|
-
multipart = @options[:multipart]
|
174
|
-
query = @options[:query]
|
175
|
-
|
176
|
-
head['content-length'] = multipart.content_length
|
177
|
-
head['content-type'] = multipart.content_type
|
178
|
-
extra_headers = {}
|
179
|
-
extra_headers = multipart.headers.reject { |k, v| %w(content-length content-type).include?(k.to_s.downcase) }
|
180
|
-
head.merge! extra_headers
|
181
|
-
|
182
|
-
request_header ||= encode_request(@req.method, @req.uri, query, @conn.opts.proxy)
|
183
|
-
request_header << encode_headers(head)
|
184
|
-
request_header << CRLF
|
185
|
-
@conn.send_data request_header
|
186
|
-
|
187
|
-
multipart.send_body(@conn)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|