mu 5.7.8 → 5.7.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.
Files changed (198) hide show
  1. data/lib/mu.rb +1 -1
  2. data/lib/mu/command.rb +18 -2
  3. data/lib/mu/command/cmd_musl.rb +165 -0
  4. data/lib/mu/command/cmd_runscale.rb +12 -8
  5. data/lib/mu/command/help.rb +1 -0
  6. data/lib/mu/har.rb +449 -0
  7. data/lib/mu/libxml.rb +21 -0
  8. data/lib/mu/maker.rb +288 -0
  9. data/lib/mu/xmlizable.rb +559 -0
  10. metadata +78 -267
  11. data/rdoc/Gemfile.html +0 -194
  12. data/rdoc/LICENSE_txt.html +0 -201
  13. data/rdoc/Mu.html +0 -478
  14. data/rdoc/Mu/Client.html +0 -461
  15. data/rdoc/Mu/Command.html +0 -338
  16. data/rdoc/Mu/Command/API.html +0 -844
  17. data/rdoc/Mu/Command/Cmd_appid.html +0 -1341
  18. data/rdoc/Mu/Command/Cmd_cli.html +0 -800
  19. data/rdoc/Mu/Command/Cmd_ddt.html +0 -1612
  20. data/rdoc/Mu/Command/Cmd_homepage.html +0 -762
  21. data/rdoc/Mu/Command/Cmd_muapi.html +0 -1363
  22. data/rdoc/Mu/Command/Cmd_netconfig.html +0 -1077
  23. data/rdoc/Mu/Command/Cmd_runscale.html +0 -1441
  24. data/rdoc/Mu/Command/Cmd_runscenario.html +0 -787
  25. data/rdoc/Mu/Command/Cmd_runverify.html +0 -893
  26. data/rdoc/Mu/Command/Cmd_scale.html +0 -1323
  27. data/rdoc/Mu/Command/Cmd_system.html +0 -677
  28. data/rdoc/Mu/Command/Curl.html +0 -751
  29. data/rdoc/Mu/Command/Help.html +0 -305
  30. data/rdoc/Mu/Curl.html +0 -243
  31. data/rdoc/Mu/Curl/Error.html +0 -304
  32. data/rdoc/Mu/Curl/Error/Authorize.html +0 -355
  33. data/rdoc/Mu/Curl/Error/Connect.html +0 -286
  34. data/rdoc/Mu/Curl/Error/DNS.html +0 -236
  35. data/rdoc/Mu/Curl/Error/Region.html +0 -307
  36. data/rdoc/Mu/Curl/Error/Status.html +0 -286
  37. data/rdoc/Mu/Curl/Error/Timeout.html +0 -286
  38. data/rdoc/Mu/Curl/Verify.html +0 -472
  39. data/rdoc/Mu/Curl/Verify/Request.html +0 -424
  40. data/rdoc/Mu/Curl/Verify/Response.html +0 -372
  41. data/rdoc/Mu/Curl/Verify/Result.html +0 -373
  42. data/rdoc/Mu/Ddt.html +0 -1347
  43. data/rdoc/Mu/Helper.html +0 -517
  44. data/rdoc/Mu/Homepage.html +0 -719
  45. data/rdoc/Mu/HttpHelper.html +0 -890
  46. data/rdoc/Mu/Muapi.html +0 -1226
  47. data/rdoc/Mu/Netconfig.html +0 -1178
  48. data/rdoc/Mu/Scale.html +0 -1359
  49. data/rdoc/Mu/System.html +0 -504
  50. data/rdoc/Object.html +0 -285
  51. data/rdoc/README_rdoc.html +0 -892
  52. data/rdoc/Rakefile.html +0 -257
  53. data/rdoc/TCTestMu.html +0 -2583
  54. data/rdoc/Test.html +0 -235
  55. data/rdoc/Test/Unit.html +0 -235
  56. data/rdoc/Test/Unit/TestCase.html +0 -236
  57. data/rdoc/Test/helper_rb.html +0 -62
  58. data/rdoc/Test/tc_test_mu_rb.html +0 -60
  59. data/rdoc/VERSION.html +0 -179
  60. data/rdoc/bin/mu.html +0 -54
  61. data/rdoc/classes/Mu.html +0 -132
  62. data/rdoc/classes/Mu/Client.html +0 -214
  63. data/rdoc/classes/Mu/Command.html +0 -129
  64. data/rdoc/classes/Mu/Command/API.html +0 -362
  65. data/rdoc/classes/Mu/Command/Cmd_appid.html +0 -238
  66. data/rdoc/classes/Mu/Command/Cmd_cli.html +0 -273
  67. data/rdoc/classes/Mu/Command/Cmd_ddt.html +0 -639
  68. data/rdoc/classes/Mu/Command/Cmd_homepage.html +0 -276
  69. data/rdoc/classes/Mu/Command/Cmd_muapi.html +0 -527
  70. data/rdoc/classes/Mu/Command/Cmd_netconfig.html +0 -399
  71. data/rdoc/classes/Mu/Command/Cmd_runscale.html +0 -220
  72. data/rdoc/classes/Mu/Command/Cmd_runscenario.html +0 -197
  73. data/rdoc/classes/Mu/Command/Cmd_runverify.html +0 -196
  74. data/rdoc/classes/Mu/Command/Cmd_scale.html +0 -511
  75. data/rdoc/classes/Mu/Command/Cmd_system.html +0 -236
  76. data/rdoc/classes/Mu/Command/Curl.html +0 -182
  77. data/rdoc/classes/Mu/Command/Help.html +0 -137
  78. data/rdoc/classes/Mu/Curl.html +0 -116
  79. data/rdoc/classes/Mu/Curl/Error.html +0 -148
  80. data/rdoc/classes/Mu/Curl/Error/Authorize.html +0 -165
  81. data/rdoc/classes/Mu/Curl/Error/Connect.html +0 -139
  82. data/rdoc/classes/Mu/Curl/Error/DNS.html +0 -113
  83. data/rdoc/classes/Mu/Curl/Error/Region.html +0 -150
  84. data/rdoc/classes/Mu/Curl/Error/Status.html +0 -139
  85. data/rdoc/classes/Mu/Curl/Error/Timeout.html +0 -139
  86. data/rdoc/classes/Mu/Curl/Verify.html +0 -207
  87. data/rdoc/classes/Mu/Curl/Verify/Request.html +0 -187
  88. data/rdoc/classes/Mu/Curl/Verify/Response.html +0 -172
  89. data/rdoc/classes/Mu/Curl/Verify/Result.html +0 -172
  90. data/rdoc/classes/Mu/Ddt.html +0 -610
  91. data/rdoc/classes/Mu/Helper.html +0 -308
  92. data/rdoc/classes/Mu/Homepage.html +0 -306
  93. data/rdoc/classes/Mu/HttpHelper.html +0 -393
  94. data/rdoc/classes/Mu/Muapi.html +0 -549
  95. data/rdoc/classes/Mu/Netconfig.html +0 -478
  96. data/rdoc/classes/Mu/Scale.html +0 -580
  97. data/rdoc/classes/Mu/System.html +0 -232
  98. data/rdoc/classes/Object.html +0 -139
  99. data/rdoc/classes/TCTestMu.html +0 -948
  100. data/rdoc/classes/Test.html +0 -107
  101. data/rdoc/classes/Test/Unit.html +0 -107
  102. data/rdoc/classes/Test/Unit/TestCase.html +0 -113
  103. data/rdoc/created.rid +0 -36
  104. data/rdoc/files/lib/mu/api/ddt_rb.html +0 -101
  105. data/rdoc/files/lib/mu/api/homepage_rb.html +0 -101
  106. data/rdoc/files/lib/mu/api/muapi_rb.html +0 -101
  107. data/rdoc/files/lib/mu/api/netconfig_rb.html +0 -101
  108. data/rdoc/files/lib/mu/api/scale_rb.html +0 -101
  109. data/rdoc/files/lib/mu/api/system_rb.html +0 -101
  110. data/rdoc/files/lib/mu/client_rb.html +0 -101
  111. data/rdoc/files/lib/mu/command/api_rb.html +0 -101
  112. data/rdoc/files/lib/mu/command/cmd_appid_rb.html +0 -119
  113. data/rdoc/files/lib/mu/command/cmd_cli_rb.html +0 -108
  114. data/rdoc/files/lib/mu/command/cmd_ddt_rb.html +0 -116
  115. data/rdoc/files/lib/mu/command/cmd_homepage_rb.html +0 -115
  116. data/rdoc/files/lib/mu/command/cmd_muapi_rb.html +0 -115
  117. data/rdoc/files/lib/mu/command/cmd_netconfig_rb.html +0 -116
  118. data/rdoc/files/lib/mu/command/cmd_runscale_rb.html +0 -119
  119. data/rdoc/files/lib/mu/command/cmd_runscenario_rb.html +0 -115
  120. data/rdoc/files/lib/mu/command/cmd_runverify_rb.html +0 -118
  121. data/rdoc/files/lib/mu/command/cmd_scale_rb.html +0 -115
  122. data/rdoc/files/lib/mu/command/cmd_system_rb.html +0 -116
  123. data/rdoc/files/lib/mu/command/curl_rb.html +0 -101
  124. data/rdoc/files/lib/mu/command/help_rb.html +0 -101
  125. data/rdoc/files/lib/mu/command_rb.html +0 -107
  126. data/rdoc/files/lib/mu/curl/error_rb.html +0 -101
  127. data/rdoc/files/lib/mu/curl/verify_rb.html +0 -101
  128. data/rdoc/files/lib/mu/helper_rb.html +0 -101
  129. data/rdoc/files/lib/mu/http_helper_rb.html +0 -101
  130. data/rdoc/files/lib/mu_rb.html +0 -121
  131. data/rdoc/files/test/helper_rb.html +0 -112
  132. data/rdoc/files/test/tc_test_mu_rb.html +0 -111
  133. data/rdoc/fr_class_index.html +0 -34
  134. data/rdoc/fr_file_index.html +0 -31
  135. data/rdoc/fr_method_index.html +0 -112
  136. data/rdoc/images/brick.png +0 -0
  137. data/rdoc/images/brick_link.png +0 -0
  138. data/rdoc/images/bug.png +0 -0
  139. data/rdoc/images/bullet_black.png +0 -0
  140. data/rdoc/images/bullet_toggle_minus.png +0 -0
  141. data/rdoc/images/bullet_toggle_plus.png +0 -0
  142. data/rdoc/images/date.png +0 -0
  143. data/rdoc/images/find.png +0 -0
  144. data/rdoc/images/loadingAnimation.gif +0 -0
  145. data/rdoc/images/macFFBgHack.png +0 -0
  146. data/rdoc/images/package.png +0 -0
  147. data/rdoc/images/page_green.png +0 -0
  148. data/rdoc/images/page_white_text.png +0 -0
  149. data/rdoc/images/page_white_width.png +0 -0
  150. data/rdoc/images/plugin.png +0 -0
  151. data/rdoc/images/ruby.png +0 -0
  152. data/rdoc/images/tag_green.png +0 -0
  153. data/rdoc/images/wrench.png +0 -0
  154. data/rdoc/images/wrench_orange.png +0 -0
  155. data/rdoc/images/zoom.png +0 -0
  156. data/rdoc/index.html +0 -884
  157. data/rdoc/js/darkfish.js +0 -116
  158. data/rdoc/js/jquery.js +0 -32
  159. data/rdoc/js/quicksearch.js +0 -114
  160. data/rdoc/js/thickbox-compressed.js +0 -10
  161. data/rdoc/lib/mu/api/ddt_rb.html +0 -52
  162. data/rdoc/lib/mu/api/homepage_rb.html +0 -52
  163. data/rdoc/lib/mu/api/muapi_rb.html +0 -52
  164. data/rdoc/lib/mu/api/netconfig_rb.html +0 -52
  165. data/rdoc/lib/mu/api/scale_rb.html +0 -52
  166. data/rdoc/lib/mu/api/system_rb.html +0 -52
  167. data/rdoc/lib/mu/client_rb.html +0 -52
  168. data/rdoc/lib/mu/command/api_rb.html +0 -52
  169. data/rdoc/lib/mu/command/cmd_appid_rb.html +0 -62
  170. data/rdoc/lib/mu/command/cmd_cli_rb.html +0 -55
  171. data/rdoc/lib/mu/command/cmd_ddt_rb.html +0 -60
  172. data/rdoc/lib/mu/command/cmd_homepage_rb.html +0 -57
  173. data/rdoc/lib/mu/command/cmd_muapi_rb.html +0 -59
  174. data/rdoc/lib/mu/command/cmd_netconfig_rb.html +0 -58
  175. data/rdoc/lib/mu/command/cmd_runscale_rb.html +0 -62
  176. data/rdoc/lib/mu/command/cmd_runscenario_rb.html +0 -57
  177. data/rdoc/lib/mu/command/cmd_runverify_rb.html +0 -61
  178. data/rdoc/lib/mu/command/cmd_scale_rb.html +0 -58
  179. data/rdoc/lib/mu/command/cmd_system_rb.html +0 -59
  180. data/rdoc/lib/mu/command/curl_rb.html +0 -52
  181. data/rdoc/lib/mu/command/help_rb.html +0 -52
  182. data/rdoc/lib/mu/command_rb.html +0 -55
  183. data/rdoc/lib/mu/curl/error_rb.html +0 -52
  184. data/rdoc/lib/mu/curl/verify_rb.html +0 -52
  185. data/rdoc/lib/mu/helper_rb.html +0 -52
  186. data/rdoc/lib/mu/http_helper_rb.html +0 -52
  187. data/rdoc/lib/mu_rb.html +0 -80
  188. data/rdoc/rdoc-style.css +0 -208
  189. data/rdoc/rdoc.css +0 -706
  190. data/test/data/app_id_stats.csv +0 -1
  191. data/test/data/app_id_status.json +0 -156
  192. data/test/data/data_cgi.msl +0 -94
  193. data/test/data/data_cgi.xml +0 -322
  194. data/test/data/default_test.csv +0 -3
  195. data/test/data/ftp_with_channel.xml +0 -1643
  196. data/test/data/irc.xml +0 -3837
  197. data/test/data/scale.json +0 -25
  198. data/test/data/test_data_cgi_error.xml +0 -35
data/lib/mu.rb CHANGED
@@ -24,7 +24,7 @@ class Mu
24
24
  "[#{datetime} #{severity}]: #{msg}\n"
25
25
  }
26
26
 
27
- check_version
27
+ #check_version
28
28
 
29
29
  kname, mname = cmd.split(':', 2)
30
30
  klass = Mu::Command.const_get kname.capitalize rescue nil
data/lib/mu/command.rb CHANGED
@@ -13,16 +13,32 @@ class Test::Unit::Assertions::AssertionMessage
13
13
  end
14
14
  end
15
15
  =end
16
+ require 'optparse'
17
+ require 'ostruct'
16
18
 
17
19
  class Mu
18
- class Command
20
+ class Command
19
21
  #include Test::Unit::Assertions
20
22
  include Helper
23
+
24
+ attr_accessor :options, :opts
25
+
26
+ def initialize
27
+ # Set defaults
28
+ @options = OpenStruct.new
29
+ @options.verbose = false
30
+
31
+ # TO DO - add additional defaults
32
+ @opts = OptionParser.new
33
+ @opts.on('-V', '--verbose') { @options.verbose = true }
34
+
35
+ end
21
36
 
22
37
  @@mu_ip = ENV['MU_IP']
23
38
  @@mu_admin_user = ENV['MU_ADMIN_USER']
24
39
  @@mu_admin_pass = ENV['MU_ADMIN_PASS']
25
- end
40
+
41
+ end # Command
26
42
  end # Mu
27
43
 
28
44
  Dir["#{File.dirname(__FILE__)}/command/*.rb"].each { |c| require c }
@@ -0,0 +1,165 @@
1
+ # File manipulation and generation class for creating musl files from other file formats.
2
+ # Example: $mu cmd_musl:from_har --ignore-css --ignore-js --endpoint <path_to_har_file>
3
+ require 'mu/maker'
4
+ require 'mu/har'
5
+
6
+ class Mu
7
+ class Command
8
+ class Cmd_musl < Command
9
+ include MuSL
10
+
11
+ attr_accessor :arguments, :scenario, :ignores, :har
12
+
13
+ def initialize
14
+ super
15
+ @options.strip_large_content = false
16
+ @options.large_content_size = nil
17
+ # TO-DO clean up variable usage and declaration
18
+ end
19
+
20
+
21
+ # displays command-line help
22
+ def cmd_help argv
23
+ setup argv
24
+ end
25
+
26
+ # checks and parses the command line arguments, displays help if missing
27
+ def setup argv
28
+ @arguments = argv
29
+ @ignores = Array.new
30
+
31
+ # If options are parsed and args are valid setup is good else show help
32
+ if parsed_options? && arguments_valid?
33
+ true
34
+ else
35
+ cmds = [
36
+ "mu cmd_musl:help",
37
+ "mu cmd_musl:from_har <options> <har_file>",
38
+ ]
39
+
40
+ puts "#{@opts}"
41
+ puts
42
+ puts "Available Commands:"
43
+ cmds.each do | c |
44
+ puts c
45
+ end
46
+ puts
47
+ puts "Outputs:"
48
+ puts "Scenario file: <harfilename>.msl by default or filename from -s"
49
+
50
+ false
51
+ end
52
+
53
+ end # setup
54
+
55
+ # Turns a har file into a musl scenario file
56
+ def cmd_from_har argv
57
+ # Check if our command line arguments are valid
58
+ if setup argv
59
+ # Get har object and hosts
60
+ har_file = @options.har_files[0]
61
+ @har = Har.new har_file, @options, @ignores
62
+ msl_file = File.open(@options.scenario,'w')
63
+ created_musl = @har.generate msl_file
64
+ msl_file.write created_musl
65
+ msl_file.close
66
+ puts "You have successfully generated a scenario: #{@options.scenario}"
67
+ else
68
+ # Handle failure logic here
69
+ raise "Invalid Command Line Options"
70
+ end
71
+ end # end cmd_from_har
72
+
73
+ # Turns a pcap into a scenario file
74
+ def cmd_from_pcap argv
75
+ # TODO LATER
76
+ raise "This command isn't implemented yet"
77
+ end
78
+
79
+
80
+
81
+
82
+ private
83
+ # Show the help banner
84
+ def help
85
+ setup ARGV
86
+ end
87
+
88
+ # True if at least one har file has been entered
89
+ def arguments_valid?
90
+ # TO DO - implement better logic here
91
+ if(@arguments.length > 0)
92
+ true
93
+ else
94
+ false
95
+ end
96
+ end # arguments valid()
97
+
98
+ # True if options were parsed or not needed
99
+ def parsed_options?
100
+ # specify the command line options and their logic
101
+
102
+ # Set a banner, displayed at the top
103
+ # of the help screen.
104
+ @opts.banner = "Usage: mu cmd_musl:<command> <options> [FILE]"
105
+
106
+ # Define the options, and what they do
107
+ @opts.on( '--ignore-non-essentials', 'Ignore App-Unknown/JS/CSS/Image files' ) do
108
+ @options.ignore = true
109
+ @ignores.push('text/css','application/javascript','application/x-javascript','text/javascript','application/octet-stream','application/x-unknown-content-type','image/png','image/jpg','image/jpeg','image/gif')
110
+ end
111
+ # Define the options, and what they do
112
+ @opts.on( '--ignore-images', 'Ignore Image files' ) do
113
+ @options.ignore = true
114
+ @ignores.push('image/png','image/jpg','image/jpeg','image/gif')
115
+ end
116
+ # Define the options, and what they do
117
+ @opts.on( '--ignore-css', 'Ignore CSS files' ) do
118
+ @options.ignore = true
119
+ @ignores.push('text/css')
120
+ end
121
+ @opts.on( '--ignore-js', 'Ignore Javascript files' ) do
122
+ @options.ignore = true
123
+ @ignores.push('application/javascript','application/x-javascript','text/javascript')
124
+ end
125
+ @opts.on( '--ignore-payload', 'Ignore the content payload' ) do
126
+ @options.ignore_payload = true
127
+ end
128
+ @opts.on('--strip-large-content [SIZE]',
129
+ Integer,
130
+ 'Replace large response content with a repeated field') do |size|
131
+ @options.strip_large_content = true
132
+ @options.large_content_size = size
133
+ end
134
+ @opts.on( '--endpoint', 'One way communication' ) do
135
+ @options.endpoint = true
136
+ end
137
+ @opts.on( '-s', '--scenario [FILENAME]', 'Specify the msl filename to be created' ) do |scenario|
138
+ @options.scenario = scenario
139
+ end
140
+ # Remove all options just leaving the harfiles
141
+ @opts.parse! @arguments rescue return false
142
+ @options.har_files = @arguments
143
+ unless @options.scenario
144
+ # Identical filename replacing the extension har with msl
145
+ begin
146
+ filename = @options.har_files[0].dup
147
+ @options.scenario = filename.gsub!(/\.har/,".msl")
148
+ rescue
149
+ # Filename is missing which means we'll show help string
150
+ return false
151
+ end
152
+
153
+ end
154
+
155
+ true
156
+ end # parsed_options()
157
+
158
+
159
+
160
+
161
+
162
+ end # Cmd_musl
163
+ end # Command
164
+ end # Mu
165
+
@@ -187,7 +187,10 @@ class Mu
187
187
  raise "Failed to read in scenario #{scenario}"
188
188
  end
189
189
 
190
- unless @testset.empty?
190
+ if @testset.empty?
191
+ @api.configure("csv", "")
192
+ else
193
+ msg "using testset [#{@testset}]", Logger::INFO
191
194
  @api.configure("csv", File.read(@testset))
192
195
  end
193
196
 
@@ -339,7 +342,7 @@ class Mu
339
342
 
340
343
  def dump_status(status, msl)
341
344
  filename = "app_id_status.json"
342
- msg "Update status to: #{File.absolute_path(filename)}", Logger::INFO
345
+ msg "Update status to: #{File.expand_path(filename)}", Logger::INFO
343
346
  f = File.open(filename, "a")
344
347
  status["filename"] = msl
345
348
  str = JSON.pretty_generate(status)
@@ -350,7 +353,7 @@ class Mu
350
353
 
351
354
  def output_csv(msl_file)
352
355
  filename = "app_id_stats.csv"
353
- msg "Update stats to: #{File.absolute_path(filename)}", Logger::INFO
356
+ msg "Update stats to: #{File.expand_path(filename)}", Logger::INFO
354
357
  unless File.exists?(filename)
355
358
  heading = "scenario,executed,errors,timeouts,client_tx_bytes,client_tx_msgs,client_rx_bytes,client_rx_msgs,server_tx_bytes,server_tx_msgs,server_rx_bytes,server_rx_msgs"
356
359
  File.open(filename, 'a'){|f| f.puts(heading)}
@@ -361,9 +364,9 @@ class Mu
361
364
 
362
365
  def output_verify_results(msl_file)
363
366
  filename = "app_id_stats.csv"
364
- msg "Update verify results to: #{File.absolute_path(filename)}", Logger::DEBUG
367
+ msg "Update verify results to: #{File.expand_path(filename)}", Logger::DEBUG
365
368
  unless File.exists?(filename)
366
- msg "Writting verify results to: #{File.absolute_path(filename)}", Logger::INFO
369
+ msg "Writting verify results to: #{File.expand_path(filename)}", Logger::INFO
367
370
  heading = "scenario, status"
368
371
  File.open(filename, 'a'){|f| f.puts(heading)}
369
372
  end
@@ -372,7 +375,7 @@ class Mu
372
375
 
373
376
  def parse_verify_response(response)
374
377
  if response.nil? # || response.empty?
375
- msg "*** error = no response received from /verify ***\n\n", Logger::ERROR
378
+ msg "*** error = no response received from /verify ***", Logger::ERROR
376
379
  @verify_response = "Error = No response from verify"
377
380
  return @verify_response
378
381
  end
@@ -382,7 +385,7 @@ class Mu
382
385
  if response["status"]["error"] == true
383
386
  @error = response["status"]["error"]
384
387
  @reason = response["status"]["reason"]
385
- msg "*** Error = #{@error}, reason = #{@reason} ***\n\n", Logger::ERROR
388
+ msg "*** Error = #{@error}, reason = #{@reason} ***", Logger::ERROR
386
389
  @verify_response = "Error = #{@error}, reason = #{@reason}"
387
390
  return @verify_response
388
391
  end
@@ -404,7 +407,7 @@ class Mu
404
407
  if status["status"]["error"] == true
405
408
  @error = status["status"]["error"]
406
409
  @reason = status["status"]["reason"]
407
- msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
410
+ msg "*** Error = #{@error}, reason = #{@reason} ***"
408
411
  return nil
409
412
  end
410
413
  end
@@ -527,6 +530,7 @@ class Mu
527
530
 
528
531
  if [ '-o', '--output' ].member? k
529
532
  $stdout.reopen(shift(k, argv), "w")
533
+ $stdout.sync = true
530
534
  next
531
535
  end
532
536
 
@@ -11,6 +11,7 @@ class Help < Command
11
11
  { :cmd => 'mu cmd_ddt:help', :help => 'Show help on using the Studio Verify Api through the command-line' },
12
12
  { :cmd => 'mu cmd_homepage:help', :help => 'Show help on using the Homepage Api through the command-line' },
13
13
  { :cmd => 'mu cmd_muapi:help', :help => 'Show help on using the Mu Api for fuzzing, templates, backup and archive' },
14
+ { :cmd => 'mu cmd_musl:help', :help => 'Show help on using the Musl Api through the command-line' },
14
15
  { :cmd => 'mu cmd_netconfig:help', :help => 'Show help on using the Netconfig Api through the command-line'},
15
16
  { :cmd => 'mu cmd_runscale:help', :help => 'Show help on running the Studio Scale app'},
16
17
  { :cmd => 'mu cmd_runscenario:help', :help => 'Show help on running the Scenario Editor Verify app' },
data/lib/mu/har.rb ADDED
@@ -0,0 +1,449 @@
1
+ # To change this template, choose Tools | Templates
2
+ # and open the template in the editor.
3
+ require 'mu/maker'
4
+ require 'mu/xmlizable'
5
+
6
+ class Har
7
+ HTTP_CONTENT_LENGTH_HEADER = 'Content-Length'
8
+ HTTP_CONTENT_TYPE_HEADER = 'Content-Type'
9
+ HTTP_CONTENT_ENCODING_HEADER = 'Content-Encoding'
10
+ HTTP_TRANSFER_ENCODING_HEADER = 'Transfer-Encoding'
11
+ HTTP_CONTENT_TRANSFER_ENCODING_HEADER = 'Content-Transfer-Encoding'
12
+
13
+ HTTP_FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded'
14
+ HTTP_TEXT_PLAIN_CONTENT_TYPE = 'text/plain'
15
+ HTTP_TEXT_HTML_CONTENT_TYPE = 'text/html'
16
+ HTTP_TEXT_XML_CONTENT_TYPE = 'text/xml'
17
+ HTTP_APPLICATION_XML_CONTENT_TYPE = 'application/xml'
18
+ HTTP_TEXT_JSON_CONTENT_TYPE = 'text/json'
19
+ HTTP_APPLICATION_JSON_CONTENT_TYPE = 'application/json'
20
+ HTTP_TEXT_JAVASCRIPT_CONTENT_TYPE = 'text/javascript'
21
+ HTTP_APPLICATION_JAVASCRIPT_CONTENT_TYPE = 'application/x-javascript'
22
+ HTTP_TEXT_CSS_CONTENT_TYPE = 'text/css'
23
+
24
+ HTTP_TEXT_CONTENT_TYPES = [ HTTP_FORM_CONTENT_TYPE,
25
+ HTTP_TEXT_PLAIN_CONTENT_TYPE,
26
+ HTTP_TEXT_HTML_CONTENT_TYPE,
27
+ HTTP_TEXT_XML_CONTENT_TYPE,
28
+ HTTP_APPLICATION_XML_CONTENT_TYPE,
29
+ HTTP_TEXT_JSON_CONTENT_TYPE,
30
+ HTTP_APPLICATION_JSON_CONTENT_TYPE,
31
+ HTTP_TEXT_JAVASCRIPT_CONTENT_TYPE,
32
+ HTTP_APPLICATION_JAVASCRIPT_CONTENT_TYPE,
33
+ HTTP_TEXT_CSS_CONTENT_TYPE ]
34
+
35
+ HTTP_GZIP_CONTENT_ENCODING = 'gzip'
36
+ HTTP_DEFLATE_CONTENT_ENCODING = 'deflate'
37
+
38
+ HTTP_EMPTY_GZIP_BODY = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00" +
39
+ "\x00\x00\x00\x00\x00\x00\x00"
40
+
41
+ HTTP_CHUNKED_TRANSFER_ENCODING = 'chunked'
42
+
43
+ HTTP_VIDEO_X_MS_WMV_CONTENT_TYPE = 'video/x-ms-wmv'
44
+ HTTP_VIDEO_X_MS_WMA_CONTENT_TYPE = 'audio/x-ms-wma'
45
+
46
+ HTTP_STREAMING_CONTENT_TYPES = [ HTTP_VIDEO_X_MS_WMV_CONTENT_TYPE,
47
+ HTTP_VIDEO_X_MS_WMA_CONTENT_TYPE ]
48
+
49
+ HTTP_CONTENT_SLICE_SIZE = 1024
50
+
51
+ MSL_ESCAPES = XMLizable::ESCAPES.dup
52
+ MSL_ESCAPES['"'.ord] = %q{\"}
53
+ MSL_ESCAPES["'".ord] = %q{\'}
54
+
55
+
56
+ attr_reader :har_file
57
+ attr_accessor :entries,:hosts,:har,:har_hosts
58
+
59
+ def initialize har_file, options, ignores
60
+ @har_file = har_file
61
+ @hosts = {}
62
+ @options = options
63
+ @ignores = ignores
64
+ begin
65
+ @har = JSON File.read(@har_file)
66
+ rescue Exception=>e
67
+ raise e
68
+ end
69
+
70
+ end
71
+
72
+ # Return a list of entries from the har file
73
+ def get_entries
74
+ @entries = @har['log']['entries']
75
+ end
76
+
77
+ def generate ios
78
+ # Attempt to create the scenario
79
+ generated = MuSL::Maker.create do |scenario|
80
+ # First declare all the hosts
81
+ scenario.hosts do |host|
82
+ self.build_hosts host
83
+ end
84
+ # Then build all the steps
85
+ scenario.steps do |step|
86
+ self.build_steps step, scenario
87
+ end # scenario.steps
88
+ end # Maker.create
89
+ end
90
+
91
+ # Return a list of hosts from the har file
92
+ def get_hosts ignores, options
93
+
94
+ # Regex to check if certain kinds of entries should be ignored, like css, js, images based on command line options
95
+ ignores_regex = ignores.join('|')
96
+
97
+ # Iterate through each har entry and parse out the important url pieces
98
+ begin
99
+ hosts_seen = Hash.new(0)
100
+ host_count = 0
101
+ @har["log"]["entries"].each_with_index do |entry, index|
102
+ # Check our command line exclusions
103
+ if(options.ignore)
104
+ next if (entry['response']['content']['mimeType'] =~ /#{ignores_regex}/o )
105
+ end
106
+
107
+ # Build the hosts list
108
+ host = nil
109
+ m = entry["musl"] = {}
110
+ m["url_object"] = URI.parse entry["request"]["url"]
111
+ m["url"] = {}
112
+ m['url']['port'] = m["url_object"].port || (m["url_object"].scheme === 'http' ? 80 : 443)
113
+ m['url']['pathname'] = m['url_object'].path || '/'
114
+ m["url"]["search"] = m["url_object"].query || ''
115
+ m["url"]["hash"] = m["url_object"].fragment || ''
116
+
117
+ # Create the host entry hash with underscores instead of dots for the host value
118
+ entry['request']['headers'].each do |header|
119
+ if (!host && header['name'].downcase === 'host')
120
+ host = header['value']
121
+ # Set the hosts_seen value to host_count and increment the host_count unless we have already seen the host
122
+ hosts_seen[host] += host_count && host_count += 1 unless hosts_seen.has_key?(host)
123
+
124
+ # OLD WAY - Substitute the dots with underscores for the musl host
125
+ # OLD WAY entry['musl'][host] = host.gsub(/[^a-zA-Z0-9_]/, '_')
126
+ entry['musl'][host] = hosts_seen[host].to_s
127
+
128
+ if entry['musl'][host].match /^[0-9]/
129
+ entry['musl'][host] = 'host_' + entry['musl'][host]
130
+ end
131
+
132
+ end
133
+ end
134
+
135
+ @hosts[host] = entry['musl'][host]
136
+ entry['musl']['host'] = entry['musl'][host]
137
+
138
+ host = nil
139
+
140
+ if entry['response']['cookies']
141
+ #p "Entry-response-cookies: #{entry['response']['cookies']}"
142
+ entry['response']['cookies'].each do |cookie|
143
+ # TODO: Need to mark the index of this entry against
144
+ # this cookie so we can search for it easily.
145
+
146
+ end
147
+ end
148
+
149
+ end
150
+ rescue Exception => e
151
+ puts e.message
152
+ puts e.backtrace.inspect
153
+ raise e
154
+ end
155
+
156
+ return @hosts
157
+ end # get_hosts
158
+
159
+ # Finds a specific cookie from the response cookies
160
+ def find_cookie name, step
161
+ if step === 0
162
+ return
163
+ end
164
+
165
+ (step-1).downto(0) {|i|
166
+ entry = @entries[i]
167
+ res = entry['response']
168
+ if (res['cookies'] && res['cookies'].length > 0)
169
+ for j in 0..res['cookies'].length do
170
+ cookie = res['cookies'][j]
171
+ unless cookie.nil?
172
+ if cookie['name'] === name
173
+ return i
174
+ end
175
+ end
176
+ end
177
+ end
178
+ }
179
+
180
+ return
181
+ end # find_cookie
182
+
183
+ # Takes the headers
184
+ def build_headers cs, headers, cookies, i
185
+ headers.each do |header|
186
+ # If this is a Cookie header, try and map the cookie
187
+ # value to a step variable preceding this step
188
+ if ('cookie' === header['name'].downcase)
189
+ #value = header['value']
190
+ value = XMLizable.escape(header['value'], MSL_ESCAPES)
191
+ for j in 0..cookies.length
192
+ cookie = cookies[j]
193
+
194
+ if defined? cookie['name']
195
+ step = self.find_cookie cookie['name'], i
196
+ # THE FOLLOWING LOGIC PROBABLY NEEDS FIXING FOR COOKIES
197
+ if (step != nil)
198
+ regex = /"(#{cookie['name']})" + "=([^;]*)"/
199
+ if value.match regex
200
+ raise "I KNOW THERE IS A PROBLE WITH THE code below"
201
+ # TODO: FIX THIS LOGIC
202
+ value = value.replace(regex, cookie['name'] + '=#{@cr' + step + '.' + cookie['name'].gsub(/[^a-zA-Z0-9_]/, '_') + '}')
203
+ end
204
+ end
205
+ end
206
+ end
207
+ cs.line(header['name'] + ': ' + value)
208
+ else
209
+ cs.line(header['name'] + ': ' + header['value'])
210
+ end
211
+
212
+ end #end headers.each
213
+ end # end build_headers
214
+
215
+
216
+ def build_postdata cs, req, entry_count, scenario
217
+
218
+ if req['postData']['params'].length > 0
219
+ cs.header('Content-Length') do
220
+ cs.length_string({'of' => "body_#{entry_count}"})
221
+ end
222
+ cs.line()
223
+
224
+ cs.block('body_' + "#{entry_count}" + ' = struct [', ']') do
225
+ #assert_equal(req['postData']['mimeType'], 'application/x-www-form-urlencoded', 'unsupported mime type')
226
+ cs.block('dsv(delimiter: "&") [',']') do
227
+ req['postData']['params'].each do |param|
228
+ cs.block('struct [',']') do
229
+ cs.string(param['name'] + '=')
230
+ cs.block('uri_percent_encode [',']') do
231
+ cs.string param['value']
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
237
+ else
238
+ unless(@options.ignore_payload)
239
+ cs.line()
240
+ self.build_payload(cs, entry_count, req, scenario)
241
+ end
242
+ end
243
+ end # end build_postdata
244
+
245
+ def build_hosts hosts
246
+ # TODO: Right now v4 is hard-coded, need to change this
247
+ hosts.create 'host_0', 'v4', 'browser'
248
+
249
+ har_hosts = self.get_hosts @ignores, @options
250
+
251
+ # Build the host entries into the scenario
252
+ har_hosts.each do |hhost,har_host_value|
253
+ hosts.create(har_hosts[hhost], 'v4', hhost)
254
+ end
255
+ end
256
+
257
+ def build_steps steps, scenario
258
+ # Create the steps
259
+ entries = self.get_entries
260
+ entry_count = 0
261
+ for i in 0..entries.length
262
+ entry = entries[i]
263
+ next unless defined? entry['musl']
264
+
265
+ m = entry['musl']
266
+ req = entry['request']
267
+ res = entry['response']
268
+ next if m.nil?
269
+
270
+ xopts = { 'src' => '&host_0', 'dst' => '&' + "#{m['host']}" }
271
+ xklass = m['url_object'].scheme === 'http' ? 'tcp' : 'ssl'
272
+ xopts['dst_port'] = m['url']['port']
273
+ # Create the xport options in the scenario
274
+ steps.xport("xport#{entry_count}", xklass, xopts)
275
+
276
+ # client_send comments for each entry
277
+ steps.comment(req["method"] + ' ' + m['url']['pathname'] + ' ' + req['httpVersion'])
278
+
279
+ # main client_send lines for each entry
280
+ steps.client_send("cs#{entry_count}","xport#{entry_count}") do |cs|
281
+ cs.line(req['method'] + ' ' + m['url']['pathname'] + m['url']['search'] + m['url']['hash'] + ' ' + req['httpVersion'])
282
+ # For each header
283
+ self.build_headers cs, req['headers'], req['cookies'], i
284
+
285
+ # For building the form post params block
286
+ if req.has_key?('postData')
287
+ self.build_postdata cs, req, entry_count, scenario
288
+ else
289
+ cs.line('Content-Length: 0')
290
+ end # end if req.has_key('postData')
291
+ cs.line()
292
+
293
+ # For building the client content payload block into the scenario
294
+ if req.has_key?('content')
295
+ self.build_payload(cs, entry_count, req, scenario)
296
+ end unless @options.ignore_payload
297
+
298
+ end # end steps.client_send
299
+
300
+ # Skip the server side if the command line option included --endpint
301
+ unless @options.endpoint
302
+ steps.server_receive("sr#{entry_count}", "cs#{entry_count}") do ||
303
+ #return nil
304
+ end
305
+
306
+ # For adding comment headers for the server side
307
+ steps.comment(res['httpVersion'] + ' ' + "#{res['status']}" + ' ' + res['statusText'])
308
+
309
+ # Build server_send portion
310
+ steps.server_send("ss#{entry_count}", "xport#{entry_count}") do |ss|
311
+ ss.line(res['httpVersion'] + ' ' + "#{res['status']}" + ' ' + res['statusText'])
312
+ res['headers'].each do |header|
313
+ ss.line(header['name'] + ': ' + header['value'])
314
+ end
315
+ ss.line()
316
+
317
+ # For building the server content payload block into the scenario
318
+ if res.has_key?('content')
319
+ build_payload ss, entry_count, res, scenario
320
+ end unless @options.ignore_payload
321
+ end # end server_send
322
+ end
323
+
324
+ # If the endpoint option is chosen only include cs 'client send' values instead of ss 'server send' values
325
+ receive_side = @options.endpoint ? 'cs' : 'ss'
326
+
327
+ # Build client_receive portion
328
+ steps.client_receive("cr#{entry_count}", "#{receive_side}#{entry_count}") do |cr|
329
+ cr.assertions do |as|
330
+ as.create('/^HTTP\\/1\\.1 (\\d+)/ == ' + "#{res['status']}")
331
+ end
332
+
333
+ if (res['cookies'] && res['cookies'].length > 0)
334
+ cr.variables do |vs|
335
+ res['cookies'].each do |cookie|
336
+ vs.create('@' + cookie['name'].gsub(/[^a-zA-Z0-9_]/, '_') + ' = ' + '/' + cookie['name'] + '=([^;]*)' + '/:1')
337
+ end
338
+ end
339
+ end
340
+ end
341
+ entry_count += 1
342
+ end
343
+ end
344
+
345
+ # If the payload is to be included, handle the inclusion logic here
346
+ def build_payload(cs_send, entry_count, req_res, scenario)
347
+ # If it is coming from the client side it will be part of the postData
348
+ payload = req_res.has_key?('content') ? req_res['content']['text'] : req_res['postData']['text']
349
+ #raise "req_res #{req_res} PAYLOAD #{payload}"
350
+ return if payload.nil?
351
+
352
+ content_encoding = false
353
+ transfer_encoding = false
354
+
355
+ # In case we need encoding types different than gzip, and chunked later on
356
+ req_res['headers'].each do |header|
357
+ if(header['name'] === 'Transfer-Encoding')
358
+ # We can do chunked
359
+ if header['value'] == HTTP_CHUNKED_TRANSFER_ENCODING
360
+ transfer_encoding = true
361
+ else
362
+ raise NotImplementedError, "Transfer-Encoding: #{header['value']}"
363
+ end
364
+
365
+ elsif(header['name'] === 'Content-Encoding')
366
+ # Check out content encoding
367
+ # We can do GZIP
368
+ if header['value'] == HTTP_GZIP_CONTENT_ENCODING
369
+ content_encoding = true
370
+ else
371
+ raise NotImplementedError, "Content-Encoding: #{header['value']}"
372
+ end
373
+
374
+ end
375
+ end
376
+
377
+ # http chunked
378
+ if transfer_encoding
379
+ cs_send.literal_no_format("http_chunk_encode(chunk_size: #{req_res['content']['size']}) [")
380
+ end
381
+
382
+ # gzip only for now
383
+ if content_encoding
384
+ cs_send.literal_no_format("gzip_compress[")
385
+ end
386
+
387
+ # If we need to replace the content with a special repeated field
388
+ if @options.strip_large_content
389
+ body = []
390
+
391
+ if req_res['content']['size'] > @options.large_content_size
392
+ # Take first 1K bytes from the content and repeat
393
+ body << payload[0, HTTP_CONTENT_SLICE_SIZE]
394
+ else
395
+ # Set response body
396
+ body << payload
397
+ end
398
+
399
+ # Yes calculate the number of 1K chunks we need to inject
400
+ count = req_res['content']['size'] / HTTP_CONTENT_SLICE_SIZE
401
+ remainder = req_res['content']['size'] % HTTP_CONTENT_SLICE_SIZE
402
+
403
+ # TODO: If there is a reminder add one more repeat count for now
404
+ if remainder > 0
405
+ count += 1
406
+ end
407
+
408
+ # Open the field
409
+ cs_send.literal_no_format("repeat(count: %d) [" % [count])
410
+ # No, write the content as binary string
411
+ cs_send.literal_no_format("\"0h")
412
+
413
+ # Write all blocks
414
+ body.each do |block|
415
+ # Write each byte in the block
416
+ block.each_byte do |byte|
417
+ cs_send.literal_no_format("%02x" % byte)
418
+ end
419
+ end
420
+ cs_send.literal_no_format("\"");
421
+ else
422
+ cs_send.literal_no_format("\"" + XMLizable.escape(payload, MSL_ESCAPES) + "\"")
423
+ end
424
+
425
+
426
+ # Close repeat field
427
+ if @options.strip_large_content
428
+ cs_send.literal_no_format("]")
429
+ end
430
+
431
+ # Close content encoding, if needed
432
+ if content_encoding
433
+ cs_send.literal_no_format("]")
434
+ end
435
+
436
+ # Close transfer encoding, if needed
437
+ if transfer_encoding
438
+ cs_send.literal_no_format("]")
439
+ end
440
+
441
+ end # build_payload()
442
+
443
+ # TO-DO: Implement this check
444
+ def text_body?
445
+ HTTP_TEXT_CONTENT_TYPES.include?(@content_type) and
446
+ not @content_transfer_encoding.to_s == 'binary' and
447
+ not @mu_content_transfer_encoding.to_s == 'binary'
448
+ end
449
+ end