Sipper 1.1.3

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 (326) hide show
  1. data/sipper/README.rb +26 -0
  2. data/sipper/b2bua_controller.rb +163 -0
  3. data/sipper/b2bua_session_mixin.rb +24 -0
  4. data/sipper/base_controller.rb +425 -0
  5. data/sipper/bin/common.rb +42 -0
  6. data/sipper/bin/generate.rb +70 -0
  7. data/sipper/bin/project.rb +44 -0
  8. data/sipper/bin/run.rb +85 -0
  9. data/sipper/bin/run_smoke.rb +8 -0
  10. data/sipper/config/log4r.xml +71 -0
  11. data/sipper/controller_class_loader.rb +29 -0
  12. data/sipper/controller_selector.rb +119 -0
  13. data/sipper/controllers/invite_controller.rb +30 -0
  14. data/sipper/controllers/order.yaml +3 -0
  15. data/sipper/custom_message.rb +4 -0
  16. data/sipper/detached_session.rb +11 -0
  17. data/sipper/docs/manual.txt +1621 -0
  18. data/sipper/generators/README +12 -0
  19. data/sipper/generators/gen_controller.rb +228 -0
  20. data/sipper/generators/gen_project.rb +45 -0
  21. data/sipper/generators/gen_test.rb +72 -0
  22. data/sipper/generators/project_template_dir/Rakefile +56 -0
  23. data/sipper/generators/project_template_dir/config/sipper.cfg +31 -0
  24. data/sipper/generators/project_template_dir/controllers/README.txt +2 -0
  25. data/sipper/generators/project_template_dir/dot_sipper.proj +2 -0
  26. data/sipper/generators/project_template_dir/logs/README.txt +2 -0
  27. data/sipper/generators/project_template_dir/tests/README.txt +2 -0
  28. data/sipper/lib/smc/statemap.rb +194 -0
  29. data/sipper/logs/dialog_info_store +0 -0
  30. data/sipper/logs/r.cmd +6 -0
  31. data/sipper/logs/r.sh +6 -0
  32. data/sipper/media/sipper_media_client.rb +268 -0
  33. data/sipper/media/sipper_media_event.rb +43 -0
  34. data/sipper/media/sipper_media_manager.rb +145 -0
  35. data/sipper/media/sipper_media_proxy.rb +60 -0
  36. data/sipper/media/sipper_offer_answer.rb +285 -0
  37. data/sipper/message.rb +512 -0
  38. data/sipper/modified_pattern_formatter.rb +119 -0
  39. data/sipper/proxy_controller.rb +143 -0
  40. data/sipper/registration.rb +52 -0
  41. data/sipper/request.rb +109 -0
  42. data/sipper/response.rb +123 -0
  43. data/sipper/ruby_ext/module.rb +27 -0
  44. data/sipper/ruby_ext/mutable_class.rb +17 -0
  45. data/sipper/ruby_ext/object.rb +38 -0
  46. data/sipper/ruby_ext/pqueue.rb +190 -0
  47. data/sipper/ruby_ext/snapshot.rb +201 -0
  48. data/sipper/ruby_ext/string.rb +18 -0
  49. data/sipper/ruby_ext/time.rb +9 -0
  50. data/sipper/run/run_sipper1.rb +28 -0
  51. data/sipper/run/run_sipper2.rb +56 -0
  52. data/sipper/sdp/sdp.rb +257 -0
  53. data/sipper/sdp/sdp_generator.rb +131 -0
  54. data/sipper/sdp/sdp_parser.rb +136 -0
  55. data/sipper/session.rb +1952 -0
  56. data/sipper/session_manager.rb +170 -0
  57. data/sipper/session_recorder.rb +190 -0
  58. data/sipper/session_state/DialogState.sm +54 -0
  59. data/sipper/session_state/DialogState_sm.rb +337 -0
  60. data/sipper/session_state/dialog_routes.rb +141 -0
  61. data/sipper/sip_headers/header.rb +632 -0
  62. data/sipper/sip_headers/sipuri.rb +352 -0
  63. data/sipper/sip_logger.rb +65 -0
  64. data/sipper/sip_message_router.rb +231 -0
  65. data/sipper/sip_test_driver_controller.rb +10 -0
  66. data/sipper/sipper.rb +329 -0
  67. data/sipper/sipper_assertions.rb +21 -0
  68. data/sipper/sipper_configurator.rb +376 -0
  69. data/sipper/sipper_http/sipper_http_request_dispatcher.rb +71 -0
  70. data/sipper/sipper_http/sipper_http_response.rb +25 -0
  71. data/sipper/stray_message_manager.rb +40 -0
  72. data/sipper/test_completion_signaling_helper.rb +77 -0
  73. data/sipper/transaction/Ict.sm +59 -0
  74. data/sipper/transaction/Ict_sm.rb +430 -0
  75. data/sipper/transaction/Ist.sm +74 -0
  76. data/sipper/transaction/Ist_sm.rb +460 -0
  77. data/sipper/transaction/Nict.sm +51 -0
  78. data/sipper/transaction/Nict_sm.rb +325 -0
  79. data/sipper/transaction/Nist.sm +59 -0
  80. data/sipper/transaction/Nist_sm.rb +356 -0
  81. data/sipper/transaction/invite_client_transaction.rb +274 -0
  82. data/sipper/transaction/invite_server_transaction.rb +319 -0
  83. data/sipper/transaction/non_invite_client_transaction.rb +230 -0
  84. data/sipper/transaction/non_invite_server_transaction.rb +263 -0
  85. data/sipper/transaction/state_machine_wrapper.rb +58 -0
  86. data/sipper/transaction/transaction.rb +212 -0
  87. data/sipper/transport/base_transport.rb +84 -0
  88. data/sipper/transport/rel_unrel.rb +19 -0
  89. data/sipper/transport/transport_and_route_resolver.rb +67 -0
  90. data/sipper/transport/udp_transport.rb +156 -0
  91. data/sipper/transport_manager.rb +33 -0
  92. data/sipper/udp_session.rb +17 -0
  93. data/sipper/util/command_element.rb +62 -0
  94. data/sipper/util/compact_converter.rb +50 -0
  95. data/sipper/util/counter.rb +26 -0
  96. data/sipper/util/digest/digest_authorizer.rb +204 -0
  97. data/sipper/util/expectation_parser.rb +164 -0
  98. data/sipper/util/locator.rb +31 -0
  99. data/sipper/util/message_fill.rb +58 -0
  100. data/sipper/util/persistence/ps_sipper_map.rb +63 -0
  101. data/sipper/util/persistence/sipper_map.rb +41 -0
  102. data/sipper/util/sipper_util.rb +305 -0
  103. data/sipper/util/timer/sip_timer_helper.rb +26 -0
  104. data/sipper/util/timer/timer_manager.rb +80 -0
  105. data/sipper/util/timer/timer_task.rb +56 -0
  106. data/sipper/util/validations.rb +44 -0
  107. data/sipper/version.rb +10 -0
  108. data/sipper_test/_test_media_uas.rb +79 -0
  109. data/sipper_test/base_test_case.rb +31 -0
  110. data/sipper_test/c_134.txt +7 -0
  111. data/sipper_test/driven_sip_test_case.rb +96 -0
  112. data/sipper_test/gold.txt +10 -0
  113. data/sipper_test/gold_res.txt +8 -0
  114. data/sipper_test/gold_sub.txt +9 -0
  115. data/sipper_test/hello_sipper.au +0 -0
  116. data/sipper_test/in_sipper.au +0 -0
  117. data/sipper_test/nonrr_proxy.rb +17 -0
  118. data/sipper_test/order_tests.yaml +4 -0
  119. data/sipper_test/rake_res.txt +399 -0
  120. data/sipper_test/rr_proxy.rb +17 -0
  121. data/sipper_test/run_test.cmd +94 -0
  122. data/sipper_test/sip_test_case.rb +104 -0
  123. data/sipper_test/test2xx_retransmission.rb +80 -0
  124. data/sipper_test/test2xx_retransmission_with_limit.rb +81 -0
  125. data/sipper_test/test2xx_retransmission_with_nist.rb +91 -0
  126. data/sipper_test/test2xx_retransmission_with_txns.rb +94 -0
  127. data/sipper_test/test_address_header.rb +66 -0
  128. data/sipper_test/test_b2bua1.rb +130 -0
  129. data/sipper_test/test_b2bua2.rb +120 -0
  130. data/sipper_test/test_b2bua3.rb +160 -0
  131. data/sipper_test/test_b2bua4.rb +130 -0
  132. data/sipper_test/test_base_controller.rb +110 -0
  133. data/sipper_test/test_base_transport.rb +37 -0
  134. data/sipper_test/test_cancel.rb +21 -0
  135. data/sipper_test/test_cancel_after2xx.rb +81 -0
  136. data/sipper_test/test_cancel_retransmission.rb +105 -0
  137. data/sipper_test/test_cancel_with481.rb +83 -0
  138. data/sipper_test/test_cancel_with487.rb +70 -0
  139. data/sipper_test/test_cancel_with_ist_without_nist.rb +99 -0
  140. data/sipper_test/test_cancel_with_nist.rb +84 -0
  141. data/sipper_test/test_cancel_without487.rb +77 -0
  142. data/sipper_test/test_command_element.rb +38 -0
  143. data/sipper_test/test_compact_converter.rb +33 -0
  144. data/sipper_test/test_controller_class_loader.rb +37 -0
  145. data/sipper_test/test_controller_selector.rb +53 -0
  146. data/sipper_test/test_controller_using_compact_headers.rb +74 -0
  147. data/sipper_test/test_controller_using_header_order.rb +85 -0
  148. data/sipper_test/test_controller_using_ict.rb +64 -0
  149. data/sipper_test/test_controller_using_ict_with_non_success.rb +72 -0
  150. data/sipper_test/test_controller_using_ict_with_tcbh.rb +24 -0
  151. data/sipper_test/test_controller_using_ict_with_tcbh_no_action.rb +24 -0
  152. data/sipper_test/test_controller_using_ist.rb +70 -0
  153. data/sipper_test/test_controller_using_ist_with_tcbh.rb +24 -0
  154. data/sipper_test/test_controller_using_nict.rb +115 -0
  155. data/sipper_test/test_controller_using_nict_with_tcbh.rb +24 -0
  156. data/sipper_test/test_controller_using_nist.rb +63 -0
  157. data/sipper_test/test_controller_using_pre_existing_rs0.rb +73 -0
  158. data/sipper_test/test_controller_using_pre_existing_rs1.rb +75 -0
  159. data/sipper_test/test_controller_using_pre_existing_rs2.rb +71 -0
  160. data/sipper_test/test_controller_using_route_set.rb +86 -0
  161. data/sipper_test/test_controller_with_sdp.rb +80 -0
  162. data/sipper_test/test_controllers/cancel/order.yaml +2 -0
  163. data/sipper_test/test_controllers/cancel/uac_cancel_controller.rb +35 -0
  164. data/sipper_test/test_controllers/cancel/uas_cancel_controller.rb +25 -0
  165. data/sipper_test/test_controllers/class_loading/ordered/first_ordered_controller.rb +5 -0
  166. data/sipper_test/test_controllers/class_loading/ordered/order.yaml +3 -0
  167. data/sipper_test/test_controllers/class_loading/ordered/recond_ordered_controller.rb +6 -0
  168. data/sipper_test/test_controllers/class_loading/ordered/second_ordered_controller.rb +6 -0
  169. data/sipper_test/test_controllers/class_loading/unordered/first_unordered_controller.rb +7 -0
  170. data/sipper_test/test_controllers/class_loading/unordered/second_unordered_controller.rb +6 -0
  171. data/sipper_test/test_controllers/ctrl_trhandler/lib/transport_filters/my_transport_handler.rb +22 -0
  172. data/sipper_test/test_controllers/ctrl_trhandler/uac_tr_handler_controller.rb +27 -0
  173. data/sipper_test/test_controllers/ctrl_trhandler/uas_tr_handler_controller.rb +21 -0
  174. data/sipper_test/test_controllers/ete/order.yaml +1 -0
  175. data/sipper_test/test_controllers/ete/uac_controller.rb +39 -0
  176. data/sipper_test/test_controllers/ete/uas_controller.rb +34 -0
  177. data/sipper_test/test_controllers/extensions/extension_uac_controller.rb +24 -0
  178. data/sipper_test/test_controllers/extensions/extension_uas_controller.rb +35 -0
  179. data/sipper_test/test_controllers/extensions/lib/sipper_extensions/my_from_extension.rb +16 -0
  180. data/sipper_test/test_controllers/ict_tcbh/lib/transaction_handlers/app_ict_handler.rb +23 -0
  181. data/sipper_test/test_controllers/ict_tcbh/uac_ict_tcbh_controller.rb +27 -0
  182. data/sipper_test/test_controllers/ict_tcbh/uac_ict_tcbh_no_action_controller.rb +28 -0
  183. data/sipper_test/test_controllers/ict_tcbh/uas_ict_tcbh_controller.rb +29 -0
  184. data/sipper_test/test_controllers/ict_tcbh/uas_ict_tcbh_no_action_controller.rb +31 -0
  185. data/sipper_test/test_controllers/ist_tcbh/lib/app_ist_handler.rb +13 -0
  186. data/sipper_test/test_controllers/ist_tcbh/uac_ist_tcbh_controller.rb +22 -0
  187. data/sipper_test/test_controllers/ist_tcbh/uas_ist_tcbh_controller.rb +31 -0
  188. data/sipper_test/test_controllers/multi_trhandlers/lib/transport_filters/in_order.yaml +2 -0
  189. data/sipper_test/test_controllers/multi_trhandlers/lib/transport_filters/my_transport_handler1.rb +21 -0
  190. data/sipper_test/test_controllers/multi_trhandlers/lib/transport_filters/my_transport_handler2.rb +21 -0
  191. data/sipper_test/test_controllers/multi_trhandlers/lib/transport_filters/out_order.yaml +2 -0
  192. data/sipper_test/test_controllers/multi_trhandlers/uac_multi_tr_handler_controller.rb +27 -0
  193. data/sipper_test/test_controllers/multi_trhandlers/uas_multi_tr_handler_controller.rb +29 -0
  194. data/sipper_test/test_controllers/multiple/lib/blank_test.rb +2 -0
  195. data/sipper_test/test_controllers/multiple/uac_info_controller.rb +21 -0
  196. data/sipper_test/test_controllers/multiple/uac_msg_controller.rb +20 -0
  197. data/sipper_test/test_controllers/multiple/uas_info_controller.rb +15 -0
  198. data/sipper_test/test_controllers/multiple/uas_msg_controller.rb +14 -0
  199. data/sipper_test/test_controllers/nict_tcbh/lib/transaction_handlers/app_nict_handler.rb +13 -0
  200. data/sipper_test/test_controllers/nict_tcbh/uac_nict_tcbh_controller.rb +26 -0
  201. data/sipper_test/test_controllers/nict_tcbh/uas_nict_tcbh_controller.rb +20 -0
  202. data/sipper_test/test_controllers/state_machine_based/lib/CreditControl.sm +43 -0
  203. data/sipper_test/test_controllers/state_machine_based/lib/CreditControl_sm.rb +194 -0
  204. data/sipper_test/test_controllers/state_machine_based/order.yaml +1 -0
  205. data/sipper_test/test_controllers/state_machine_based/uac_message_controller.rb +34 -0
  206. data/sipper_test/test_controllers/state_machine_based/uas_message_controller.rb +44 -0
  207. data/sipper_test/test_controllers/stray_message/lib/sipper_extensions/my_stray_handler.rb +9 -0
  208. data/sipper_test/test_controllers/stray_message/stray_uac_controller.rb +24 -0
  209. data/sipper_test/test_controllers/stray_message/stray_uas_controller.rb +31 -0
  210. data/sipper_test/test_controllers/string/order.yaml +1 -0
  211. data/sipper_test/test_controllers/string/uac_controller.rb +29 -0
  212. data/sipper_test/test_controllers/string/uas_controller.rb +22 -0
  213. data/sipper_test/test_controllers/test_controller.rb +24 -0
  214. data/sipper_test/test_detached_session1.rb +78 -0
  215. data/sipper_test/test_dialog_routes.rb +139 -0
  216. data/sipper_test/test_digest_challenge1.rb +89 -0
  217. data/sipper_test/test_digest_challenge2.rb +90 -0
  218. data/sipper_test/test_dynamic_parse.rb +249 -0
  219. data/sipper_test/test_empty_sdp.rb +89 -0
  220. data/sipper_test/test_ete.rb +37 -0
  221. data/sipper_test/test_expectation_parser.rb +76 -0
  222. data/sipper_test/test_extensions.rb +28 -0
  223. data/sipper_test/test_freeze.rb +81 -0
  224. data/sipper_test/test_generated.rb +90 -0
  225. data/sipper_test/test_header_parameters.rb +75 -0
  226. data/sipper_test/test_header_parse.rb +141 -0
  227. data/sipper_test/test_http_client1.rb +84 -0
  228. data/sipper_test/test_http_client2.rb +90 -0
  229. data/sipper_test/test_ict_with_timeout.rb +62 -0
  230. data/sipper_test/test_in_dialog_request.rb +61 -0
  231. data/sipper_test/test_inline_controller.rb +67 -0
  232. data/sipper_test/test_invite_client_transaction.rb +272 -0
  233. data/sipper_test/test_invite_replace.rb +147 -0
  234. data/sipper_test/test_invite_retransmission.rb +90 -0
  235. data/sipper_test/test_invite_server_transaction.rb +208 -0
  236. data/sipper_test/test_lower_cseq.rb +79 -0
  237. data/sipper_test/test_media.rb +52 -0
  238. data/sipper_test/test_message.rb +392 -0
  239. data/sipper_test/test_method_specific_response_handling.rb +81 -0
  240. data/sipper_test/test_multi_homed1.rb +127 -0
  241. data/sipper_test/test_multi_homed2.rb +109 -0
  242. data/sipper_test/test_multi_homed_duplicate.rb +87 -0
  243. data/sipper_test/test_multi_homed_with_detached.rb +88 -0
  244. data/sipper_test/test_multiple.rb +49 -0
  245. data/sipper_test/test_multiple_contacts.rb +89 -0
  246. data/sipper_test/test_non2xx_retransmission_with_ist.rb +87 -0
  247. data/sipper_test/test_non_invite_client_transaction.rb +210 -0
  248. data/sipper_test/test_non_invite_retransmission.rb +91 -0
  249. data/sipper_test/test_non_invite_server_transaction.rb +202 -0
  250. data/sipper_test/test_offer_answer_prack.rb +103 -0
  251. data/sipper_test/test_pickup.rb +258 -0
  252. data/sipper_test/test_prack.rb +105 -0
  253. data/sipper_test/test_prack_store_and_dispatch.rb +101 -0
  254. data/sipper_test/test_prack_timer.rb +105 -0
  255. data/sipper_test/test_ps_sipper_map.rb +56 -0
  256. data/sipper_test/test_re_invite_uas_ongoing_ict.rb +81 -0
  257. data/sipper_test/test_re_invite_uas_ongoing_ist.rb +84 -0
  258. data/sipper_test/test_re_invite_with_ongoing_ict.rb +101 -0
  259. data/sipper_test/test_re_invite_with_ongoing_ist.rb +89 -0
  260. data/sipper_test/test_recorder_swap.rb +157 -0
  261. data/sipper_test/test_refer.rb +121 -0
  262. data/sipper_test/test_registeration_clearing.rb +97 -0
  263. data/sipper_test/test_registrar.rb +109 -0
  264. data/sipper_test/test_registration_controller.rb +73 -0
  265. data/sipper_test/test_registration_timeout.rb +90 -0
  266. data/sipper_test/test_remote_controller.rb +39 -0
  267. data/sipper_test/test_remote_target_update_on2xx.rb +140 -0
  268. data/sipper_test/test_request.rb +106 -0
  269. data/sipper_test/test_response.rb +40 -0
  270. data/sipper_test/test_response_without_to_tag.rb +92 -0
  271. data/sipper_test/test_rport.rb +88 -0
  272. data/sipper_test/test_sdp.rb +91 -0
  273. data/sipper_test/test_sdp_parser.rb +145 -0
  274. data/sipper_test/test_session.rb +276 -0
  275. data/sipper_test/test_session_callback_handler.rb +68 -0
  276. data/sipper_test/test_session_lifetime.rb +66 -0
  277. data/sipper_test/test_session_manager.rb +141 -0
  278. data/sipper_test/test_session_recorder.rb +145 -0
  279. data/sipper_test/test_session_state_user_defined.rb +84 -0
  280. data/sipper_test/test_session_states.rb +91 -0
  281. data/sipper_test/test_simple_dialog_state.rb +86 -0
  282. data/sipper_test/test_simple_re_invite.rb +86 -0
  283. data/sipper_test/test_sip_uri.rb +234 -0
  284. data/sipper_test/test_sipper_util.rb +45 -0
  285. data/sipper_test/test_smc_controller.rb +17 -0
  286. data/sipper_test/test_smoke.rb +80 -0
  287. data/sipper_test/test_stray.rb +28 -0
  288. data/sipper_test/test_stray_inline.rb +89 -0
  289. data/sipper_test/test_stray_res_acked.rb +103 -0
  290. data/sipper_test/test_stray_respond.rb +104 -0
  291. data/sipper_test/test_stray_retry.rb +92 -0
  292. data/sipper_test/test_stray_retry_failure.rb +93 -0
  293. data/sipper_test/test_stray_retry_initial.rb +100 -0
  294. data/sipper_test/test_strict_router_with_angled.rb +84 -0
  295. data/sipper_test/test_string_record.rb +31 -0
  296. data/sipper_test/test_subscribe_notify.rb +141 -0
  297. data/sipper_test/test_subscribe_notify_client_timeout.rb +158 -0
  298. data/sipper_test/test_subscribe_notify_dialog.rb +146 -0
  299. data/sipper_test/test_subscribe_notify_expires.rb +155 -0
  300. data/sipper_test/test_subscribe_notify_multiple_subscription.rb +157 -0
  301. data/sipper_test/test_subscribe_notify_server_timeout.rb +144 -0
  302. data/sipper_test/test_subsequent_unsent.rb +88 -0
  303. data/sipper_test/test_target_refresh_proxy_detached.rb +128 -0
  304. data/sipper_test/test_target_refresh_proxy_udp.rb +130 -0
  305. data/sipper_test/test_target_refresh_rr_proxy_udp.rb +133 -0
  306. data/sipper_test/test_target_refresh_with_new_port.rb +158 -0
  307. data/sipper_test/test_target_refresh_with_proxy1.rb +113 -0
  308. data/sipper_test/test_target_refresh_with_rr_update_proxy.rb +145 -0
  309. data/sipper_test/test_target_refresh_with_update_proxy.rb +144 -0
  310. data/sipper_test/test_target_refresh_with_update_proxy2.rb +139 -0
  311. data/sipper_test/test_timer_manager.rb +71 -0
  312. data/sipper_test/test_timer_task.rb +60 -0
  313. data/sipper_test/test_transport_handler.rb +19 -0
  314. data/sipper_test/test_transport_multi_handler.rb +18 -0
  315. data/sipper_test/test_udp_transport.rb +119 -0
  316. data/sipper_test/test_unparsed.rb +70 -0
  317. data/sipper_test/test_validations.rb +69 -0
  318. data/sipper_test/test_with_rr_proxy.rb +111 -0
  319. data/sipper_test/testmediacontroller.rb +71 -0
  320. data/sipper_test/tracing.rb +23 -0
  321. data/sipper_test/transaction_test_helper.rb +176 -0
  322. data/sipper_test/transport_filters.rb +26 -0
  323. data/sipper_test/ts_sipper.rb +91 -0
  324. data/sipper_test/ts_smoke.rb +3 -0
  325. data/sipper_test/tt.cmd +20 -0
  326. metadata +455 -0
@@ -0,0 +1,512 @@
1
+ require 'sip_logger'
2
+ require 'ruby_ext/string'
3
+ require 'util/timer/timer_task'
4
+ require 'sip_headers/header'
5
+ require 'util/compact_converter'
6
+ require 'util/sipper_util'
7
+ require 'media/sipper_media_event'
8
+ require 'sipper_http/sipper_http_response'
9
+
10
+ class Message
11
+
12
+ include SipLogger
13
+ include Enumerable
14
+
15
+ attr_accessor :incoming, :rcvd_from_info, :rcvd_at_info, :transaction
16
+
17
+ attr_reader :sdp
18
+
19
+ SIP_VER_PATT = /((?i)sip)\/[0-9]+\.[0-9]+/
20
+ TAGP_C = /(tag=)(.*?);/
21
+ TAGP_E = /(tag=)(.*?)$/
22
+
23
+ def initialize(*hh)
24
+ @headers = {}
25
+ define_from_hash hh[0] unless hh[0].nil?
26
+ #populated only for incoming messages
27
+ @rcvd_from_info = nil
28
+ @separate_mv_hdrs ||= []
29
+ end
30
+
31
+ def attributes
32
+ @attrs ||= {}
33
+ end
34
+
35
+ def is_request?
36
+ self.class == Request
37
+ end
38
+
39
+ def is_response?
40
+ self.class == Response
41
+ end
42
+
43
+ def Message.parse msg
44
+ # If the message is a SIP message received on wire then it of the form
45
+ #["msg", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
46
+ # otherwise it could be a timer task
47
+ return msg if msg.class <= SIP::TimerTask
48
+ return msg if msg.class <= Media::SipperMediaEvent
49
+ return msg if msg.class <= SipperHttp::SipperHttpResponse
50
+ msg_arr = msg[0].split("\n")
51
+ #SipLogger['siplog::message'].debug("In Message.parse_msg, rcvd from info is #{msg[1]}")
52
+ idx = SIP_VER_PATT =~ msg_arr[0]
53
+ raise ArgumentError, "Not a SIP message" unless idx
54
+ case
55
+ when idx==0
56
+ SipLogger['siplog::message'].debug("Parsing received response")
57
+ r = Response.parse msg_arr
58
+ when idx > 0
59
+ SipLogger['siplog::message'].debug("Parsing received request")
60
+ r = Request.parse( msg_arr, :received_ip=>msg[1][3], :received_port=>msg[1][1] )
61
+ else
62
+ raise ArgumentError, "Not a SIP message"
63
+ end
64
+ r.rcvd_from_info = msg[1] #["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]
65
+ r.rcvd_at_info = msg[2] #[ip, port]
66
+ return r
67
+ end
68
+
69
+
70
+ def each &block
71
+ @headers.each(&block)
72
+ end
73
+
74
+ def each_header &block
75
+ @headers.each_key(&block)
76
+ end
77
+
78
+ def each_value &block
79
+ @headers.each_value(&block)
80
+ end
81
+
82
+ def define_from_hash(header_hash)
83
+ logi("Defining headers from hash #{header_hash}")
84
+ header_hash.each { |k,v| self.send((k.to_s<<"=").to_sym, v)}
85
+ end
86
+
87
+ # The method to copy headers from a message.If you provide the particular headers,
88
+ # it will copy only those headers, else will copy all the headers.
89
+ def copy_from(from_msg, *hdrs)
90
+ logd("copy_from: copying headers #{hdrs.join(",")}")
91
+ if hdrs[0] == :_sipper_all
92
+ from_msg.each {|k,v| self[k] = v}
93
+ else
94
+ hdrs.each {|x| self[x] = from_msg[x] if from_msg[x]}
95
+ end
96
+
97
+ self
98
+ end
99
+
100
+ # This method is used to assign arbitrary values to any headers including
101
+ # system headers.The first argument is a symbol indicating the header name
102
+ # and second argument is the value.
103
+ def assign_unparsed(hdr_name, arg)
104
+ unless self.respond_to? hdr_name.to_sym
105
+ self.send((hdr_name.to_s+"=").to_sym, arg) { "do not call" }
106
+ end
107
+ @headers[hdr_name.to_sym] = if arg.nil?
108
+ nil
109
+ else
110
+ if arg.is_a?(SipHeaders::Header)
111
+ a
112
+ elsif arg.is_a?(Array)
113
+ a = arg.dup
114
+ else
115
+ a = arg.split(",")
116
+ end
117
+ unless hdr_name.to_s == "content"
118
+ b = a.map do |z|
119
+ _find_parser_and_parse(hdr_name.to_sym, z, false)
120
+ end # map
121
+ else
122
+ b = a
123
+ end # unless content
124
+ b
125
+ end
126
+ end
127
+
128
+ def method_missing(m,*a, &block)
129
+ if (md=(/=$/.match(m.to_s)))
130
+ m_name = md.pre_match
131
+ m_name_plural = m_name+"s"
132
+ Message.class_eval do
133
+
134
+ define_method(m_name.to_sym) do # accessor
135
+ if @headers[m_name.to_sym]
136
+ val = @headers[m_name.to_sym][0] || ''
137
+ else
138
+ nil
139
+ end
140
+ end
141
+
142
+ define_method(m_name_plural.to_sym) do # accessor for mv headers
143
+ @headers[m_name.to_sym]
144
+ end
145
+
146
+ define_method(("add_"+m_name).to_sym) do |arg| #append at the end
147
+ (@headers[m_name.to_sym] ||= []) << _find_parser_and_parse(m_name.to_sym, arg, true)
148
+ self
149
+ end
150
+
151
+ define_method(m) do |arg| #mutator
152
+ s_name = m_name.to_sym
153
+ if @headers[s_name] &&
154
+ @headers[s_name][0].respond_to?(:frozen_str) &&
155
+ @headers[s_name][0].frozen_str
156
+ then
157
+ return @headers[s_name]
158
+ end
159
+ @headers[s_name] = if arg.nil?
160
+ nil
161
+ else
162
+ if arg.is_a?(SipHeaders::Header)
163
+ a = [arg]
164
+ elsif arg.is_a?(Array)
165
+ a = arg.dup
166
+ elsif (m_name =~ /authenticat/ || m_name =~ /authorization/) # auth headers have "," in hdr values
167
+ a = [arg]
168
+ elsif m_name == "content"
169
+ a = arg.split("\r\n").map { |y| y.strip }
170
+ else
171
+ a = arg.split(",").map { |y| y.strip }
172
+ end
173
+ unless (m_name == "content")
174
+ b = a.map do |z|
175
+ _find_parser_and_parse(s_name, z, true)
176
+ end # map
177
+ else
178
+ b = a
179
+ end # unless content
180
+ b
181
+ end # assign from if
182
+ end # define_method
183
+
184
+ define_method(("pop_"+m_name).to_sym) do #pop top
185
+ if @headers[m_name.to_sym]
186
+ p = @headers[m_name.to_sym].shift
187
+ if @headers[m_name.to_sym].length == 0
188
+ @headers[m_name.to_sym] = nil
189
+ end
190
+ return p
191
+ else
192
+ nil
193
+ end
194
+ end
195
+
196
+ define_method(("push_"+m_name).to_sym) do |arg| #push top
197
+ if @headers[m_name.to_sym] && (hdr_sz=@headers[m_name.to_sym].size) > 0
198
+ @headers[m_name.to_sym].reverse! if hdr_sz > 1
199
+ @headers[m_name.to_sym].push(_find_parser_and_parse(m_name.to_sym, arg, true))
200
+ @headers[m_name.to_sym].reverse!
201
+ else
202
+ (@headers[m_name.to_sym] ||= []) << _find_parser_and_parse(m_name.to_sym, arg, true)
203
+ end
204
+ self
205
+ end
206
+
207
+ end #class_eval
208
+
209
+ logi("Adding header #{m}")
210
+ unless block_given?
211
+ send(m, *a, &block)
212
+ end
213
+ else
214
+ raise NoMethodError, "#{m}"
215
+ end
216
+ end
217
+
218
+ def [](hdr)
219
+ @headers[hdr]
220
+ end
221
+
222
+ def []= (hdr, val)
223
+ self.send((hdr.to_s+"=").to_sym, val)
224
+ end
225
+
226
+ def _find_parser_and_parse(hname, val, parse_option)
227
+ SipperUtil.find_parser_and_parse(hname, val, parse_option)
228
+ end
229
+ private :_find_parser_and_parse
230
+
231
+
232
+ # This method is to be invoked when the header is created but the content
233
+ # is not parsed. The string provided in "val" is directly written as the
234
+ # header content. The consequence is also a by-passing of any validations.
235
+ def assign_header_without_parse(hdr, val)
236
+ if self.respond_to?(hdr)
237
+ self.send(hdr, val) { false }
238
+ else
239
+ self.method_missing((hdr.to_s+"=").to_sym, val) { false }
240
+ end
241
+ end
242
+
243
+ def content_len
244
+ if @headers.has_key? :content
245
+ return @headers[:content].join("\r\n").length+2 # for the last element \r\n which doesnt add in join
246
+ else
247
+ return 0
248
+ end
249
+ end
250
+
251
+ # extracts the from tag from the message without a full parse of the header.
252
+ def from_tag
253
+ self.from.tag
254
+ end
255
+
256
+ # extracts the to tag from the message without a full parse of the header.
257
+ def to_tag
258
+ self.to.tag
259
+ end
260
+
261
+ # takes a full From/To header and just returns the value of the tag
262
+ def tag str
263
+ m = TAGP_C.match(str)
264
+ m = TAGP_E.match(str) unless m
265
+ if m
266
+ return m[2]
267
+ else
268
+ return nil
269
+ end
270
+ end
271
+
272
+
273
+ def parse_headers arr
274
+ if logger.debug?
275
+ #logd("In parse headers with array :")
276
+ #arr.each_with_index {|x,i| logd("## arr[#{i}] = #{x}")}
277
+ end
278
+ content_idx = -1
279
+ arr.each_with_index do |str, idx|
280
+ logd("parsing header : "+str)
281
+ if !str || str.strip.length == 0 # \r\n\r\n before content
282
+ content_idx = idx+1
283
+ break
284
+ end
285
+ h = str.split(":",2)
286
+ str_dc=h[0].strip.downcase
287
+ #todo think about a lookup at the message level of the
288
+ #header names and a symbols for fast processing.
289
+ str_dc = SipperUtil::CompactConverter.get_expanded(str_dc) if str_dc.size==1 && SipperUtil::CompactConverter.has_expanded_form?(str_dc)
290
+ hn = SipperUtil.methodize(str_dc) # header name
291
+ if @headers[hn.to_sym]
292
+ self.send(("add_"+hn.to_s).to_sym, h[1])
293
+ else
294
+ self.send((hn.to_s+"=").to_sym, h[1])
295
+ end
296
+ end
297
+ @headers[:content_length][0].freeze if @headers[:content_length]
298
+ #logd("content_idx = #{content_idx} and arr.length = #{arr.length}")
299
+ parse_content arr[content_idx..-1] if ((content_idx>0) && (content_idx< arr.length))
300
+ end
301
+
302
+ # Each value in the header hash is an array for MV, content is also a single array.
303
+ #
304
+ # 18.3 Framing
305
+ # In the case of message-oriented transports (such as UDP), if the message has a
306
+ # Content-Length header field, the message body is assumed to contain that many bytes.
307
+ # If there are additional bytes in the transport packet beyond the end of the body,
308
+ # they MUST be discarded. If the transport packet ends before the end of the message
309
+ # body, this is considered an error. If the message is a response, it MUST be discarded.
310
+ # If the message is a request, the element SHOULD generate a 400 (Bad Request) response.
311
+ # If the message has no Content-Length header field, the message body is assumed to end at
312
+ # the end of the transport packet.
313
+ # In the case of stream-oriented transports such as TCP, the Content-Length header field
314
+ # indicates the size of the body. The Content-Length header field MUST be used with
315
+ # stream oriented transports .
316
+ #
317
+ def parse_content arr
318
+ # see comment above on framing
319
+ if SipperConfigurator[:ProtocolCompliance]=='strict'
320
+ s = 0
321
+ len = self.content_length.to_s.to_i
322
+ self[:content] = arr.map do |x|
323
+ if s+x.length <= len
324
+ s+=x.length
325
+ x.strip
326
+ else
327
+ ws = x.length - x.strip.length
328
+ en = len-s-ws # consider white spaces upfront, as we will add \r\n while formatting
329
+ s = len # to stop loop
330
+ if en>0
331
+ x[0...en].strip
332
+ else
333
+ nil
334
+ end
335
+ end
336
+ end
337
+ self[:content] = self[:content].select {|x| x } # non nil
338
+ else # lax compliance
339
+ self[:content] = arr.map {|x| x.strip}
340
+ end
341
+ logw "Actual content length #{content_len} different from Content-Length header #{content_length}" if content_len != content_length.to_s.to_i
342
+ end
343
+
344
+ # todo test this feature
345
+ def format_as_separate_headers_for_mv(*hdrs)
346
+ @separate_mv_hdrs ||= []
347
+ @separate_mv_hdrs += hdrs
348
+ end
349
+
350
+ def header_order=(hoarr)
351
+ @header_order_arr = hoarr
352
+ end
353
+
354
+ def compact_headers=(charr)
355
+ @compact_headers = charr
356
+ end
357
+
358
+ def _header_name(k)
359
+ if @compact_headers && ((@compact_headers.include?(:all_headers)||@compact_headers.include?(k)) && SipperUtil::CompactConverter.has_compact_form?(k))
360
+ SipperUtil::CompactConverter.get_compact(k)
361
+ else
362
+ SipperUtil.headerize(k)
363
+ end
364
+ end
365
+
366
+
367
+ # gives the transaction id for the message. If the message is a RFC3261 message
368
+ # then the branch is taken otherwise it is computed from the message.
369
+ def txn_id
370
+ #todo check for magic cookie and evaluate the txn_id if the message is
371
+ #not a 3261 message
372
+ self.via.branch
373
+ end
374
+
375
+ # Returns the body of the message, which is another name for content but
376
+ # message.content does not return proper contents of the message. Instead
377
+ # message.contents (note the s in the end) returns the contents as an array.
378
+ # This method however returns the properly formatted message body.
379
+ def body
380
+ b = nil
381
+ if @headers[:content]
382
+ b = ""
383
+ @headers[:content].each {|x| b << x << "\r\n"}
384
+ end
385
+ b
386
+ end
387
+
388
+ def sdp=(sdp)
389
+ @sdp = sdp
390
+ sdp_csv_content = @sdp.format_sdp("\r\n")
391
+ self.content = sdp_csv_content
392
+ self.content_type = 'application/sdp'
393
+ end
394
+
395
+ # takes [body] and type as two arguments
396
+ def set_body(b, type)
397
+ self.content = b.join("\r\n")
398
+ self.content_type = type
399
+ end
400
+
401
+ def _format_message(smsg)
402
+ if @header_order_arr
403
+ ordered_headers = @header_order_arr + (@headers.keys - @header_order_arr)
404
+ else
405
+ ordered_headers = @headers.keys
406
+ end
407
+ ordered_headers.each do |k|
408
+ next if k == :content
409
+ v = @headers[k]
410
+ next if v.nil? # nil valued headers are hidden and popped headers leave []
411
+ if @separate_mv_hdrs && @separate_mv_hdrs.include?(k)
412
+ v.each {|val| smsg << _header_name(k) << ":" << " " << val.to_s << "\r\n" }
413
+ else
414
+ smsg << _header_name(k) << ":" << " " << (v.map {|val| val.to_s}).join(", ") << "\r\n"
415
+ end
416
+ end
417
+
418
+ smsg << "\r\n"
419
+ if ((_cl=content_len) > 0)
420
+ smsg << self.body
421
+ end
422
+ smsg
423
+ end
424
+
425
+ def short_to_s
426
+ if is_request?
427
+ self.method
428
+ elsif is_response?
429
+ self.code.to_s
430
+ end
431
+ end
432
+
433
+ private :tag, :_header_name
434
+ protected :_format_message
435
+
436
+ end
437
+
438
+ unless defined? PRIMED
439
+ addr = "sip:nasir@sipper.com"
440
+ f = "foo"
441
+ m = Message.new
442
+ m.accept = f
443
+ m.accept_contact = f
444
+ m.accept_encoding = f
445
+ m.accept_language = f
446
+ m.allow = f
447
+ m.authentication_info = 'nextnonce="d", qop=auth, nc=00000001, cnonce="0", rspauth="6"'
448
+ m.authorization = 'Digest username="b", realm="b.com", nonce="d", uri="sip:b@b.c", qop=auth, nc=00000001, cnonce="0", response="6", opaque="5"'
449
+ m.call_id = f
450
+ m.call_info = f
451
+ m.contact = addr
452
+ m.content_disposition = f
453
+ m.content_encoding = f
454
+ m.content_language = f
455
+ m.content_length = "1"
456
+ m.content_type = f
457
+ m.cseq = "1"
458
+ m.date = f
459
+ m.error_info = f
460
+ m.event = f
461
+ m.expires = "1"
462
+ m.from = addr
463
+ m.hide = f
464
+ m.history_info = f
465
+ m.identity = f
466
+ m.identity_info = f
467
+ m.in_reply_to = f
468
+ m.join = f
469
+ m.max_forwards = "1"
470
+ m.mime_version = f
471
+ m.min_expires = "1"
472
+ m.min_se = "1"
473
+ m.organization = f
474
+ m.p_asserted_identity = addr
475
+ m.p_charging_vector = f
476
+ m.p_visited_network_id = f
477
+ m.path = addr
478
+ m.priority = "1"
479
+ m.privacy = f
480
+ m.proxy_authenticate = 'Digest realm="a.c", domain="sip:s.c", nonce="f", stale=FALSE, algorithm=MD5'
481
+ m.proxy_authorization = 'Digest username="b", realm="b.com", nonce="d", uri="sip:b@b.c", qop=auth, nc=00000001, cnonce="0", response="6", opaque="5"'
482
+ m.proxy_require = f
483
+ m.rack = f
484
+ m.reason = f
485
+ m.record_route = addr
486
+ m.refer_sub = "false"
487
+ m.refer_to = addr
488
+ m.referred_by = addr
489
+ m.reject_contact = f
490
+ m.replaces = f
491
+ m.reply_to = addr
492
+ m.request_disposition = f
493
+ m.require = f
494
+ m.retry_after = "1"
495
+ m.route = addr
496
+ m.rseq = "1"
497
+ m.server = f
498
+ m.service_route = addr
499
+ m.session_expires = f
500
+ m.subject = f
501
+ m.subscription_state = f
502
+ m.supported = f
503
+ m.target_dialog = f
504
+ m.timestamp = f
505
+ m.to = addr
506
+ m.unsupported = f
507
+ m.user_agent = f
508
+ m.via = "SIP/2.0/UDP 127.0.0.1:6061;branch=z9hG4bK-2352-1-0"
509
+ m.warning = f
510
+ m.www_authenticate = 'Digest realm="a.c", domain="sip:s.c", nonce="f", stale=FALSE, algorithm=MD5'
511
+ PRIMED = true
512
+ end