mu 5.7.8 → 5.7.9

Sign up to get free protection for your applications and to get access to all the features.
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