PageRenderTime 56ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/epan/dissectors/packet-json.c

https://github.com/labx-technologies-llc/wireshark
C | 599 lines | 457 code | 97 blank | 45 comment | 56 complexity | 88e1bfe03918a544a36ff59e245f6d24 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. /* packet-json.c
  2. * Routines for JSON dissection
  3. * References:
  4. * RFC 4627: http://tools.ietf.org/html/rfc4627
  5. * Website: http://json.org/
  6. *
  7. * Copyright 2010, Jakub Zawadzki <darkjames-ws@darkjames.pl>
  8. *
  9. * $Id$
  10. *
  11. * Wireshark - Network traffic analyzer
  12. * By Gerald Combs <gerald@wireshark.org>
  13. * Copyright 1998 Gerald Combs
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * as published by the Free Software Foundation; either version 2
  18. * of the License, or (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program; if not, write to the Free Software
  27. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  28. */
  29. #define NEW_PROTO_TREE_API
  30. #include "config.h"
  31. #include <glib.h>
  32. #include <epan/emem.h>
  33. #include <epan/packet.h>
  34. #include <epan/tvbparse.h>
  35. static gint ett_json = -1;
  36. static gint ett_json_array = -1;
  37. static gint ett_json_object = -1;
  38. static gint ett_json_member = -1;
  39. static header_field_info *hfi_json = NULL;
  40. #define JSON_HFI_INIT HFI_INIT(proto_json)
  41. static header_field_info hfi_json_array JSON_HFI_INIT =
  42. { "Array", "json.array", FT_NONE, BASE_NONE, NULL, 0x00, "JSON array", HFILL };
  43. static header_field_info hfi_json_object JSON_HFI_INIT =
  44. { "Object", "json.object", FT_NONE, BASE_NONE, NULL, 0x00, "JSON object", HFILL };
  45. static header_field_info hfi_json_member JSON_HFI_INIT =
  46. { "Member", "json.member", FT_NONE, BASE_NONE, NULL, 0x00, "JSON object member", HFILL };
  47. #if 0
  48. /* XXX */
  49. static header_field_info hfi_json_member_key JSON_HFI_INIT =
  50. { "Key", "json.member.key", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL };
  51. #endif
  52. static header_field_info hfi_json_value_string JSON_HFI_INIT = /* FT_STRINGZ? */
  53. { "String value", "json.value.string", FT_STRING, BASE_NONE, NULL, 0x00, "JSON string value", HFILL };
  54. static header_field_info hfi_json_value_number JSON_HFI_INIT = /* FT_DOUBLE/ FT_INT64? */
  55. { "Number value", "json.value.number", FT_STRING, BASE_NONE, NULL, 0x00, "JSON number value", HFILL };
  56. static header_field_info hfi_json_value_false JSON_HFI_INIT =
  57. { "False value", "json.value.false", FT_NONE, BASE_NONE, NULL, 0x00, "JSON false value", HFILL };
  58. static header_field_info hfi_json_value_null JSON_HFI_INIT =
  59. { "Null value", "json.value.null", FT_NONE, BASE_NONE, NULL, 0x00, "JSON null value", HFILL };
  60. static header_field_info hfi_json_value_true JSON_HFI_INIT =
  61. { "True value", "json.value.true", FT_NONE, BASE_NONE, NULL, 0x00, "JSON true value", HFILL };
  62. static tvbparse_wanted_t* want;
  63. static tvbparse_wanted_t* want_ignore;
  64. static dissector_handle_t text_lines_handle;
  65. typedef enum {
  66. JSON_TOKEN_INVALID = -1,
  67. JSON_TOKEN_NUMBER = 0,
  68. JSON_TOKEN_STRING,
  69. JSON_TOKEN_FALSE,
  70. JSON_TOKEN_NULL,
  71. JSON_TOKEN_TRUE,
  72. /* not really tokens ... */
  73. JSON_OBJECT,
  74. JSON_ARRAY
  75. } json_token_type_t;
  76. typedef struct {
  77. ep_stack_t stack;
  78. } json_parser_data_t;
  79. static void
  80. dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  81. {
  82. proto_tree *json_tree = NULL;
  83. proto_item *ti = NULL;
  84. json_parser_data_t parser_data;
  85. tvbparse_t *tt;
  86. const char *data_name;
  87. int offset;
  88. data_name = pinfo->match_string;
  89. if (!(data_name && data_name[0])) {
  90. /*
  91. * No information from "match_string"
  92. */
  93. data_name = (char *)(pinfo->private_data);
  94. if (!(data_name && data_name[0])) {
  95. /*
  96. * No information from "private_data"
  97. */
  98. data_name = NULL;
  99. }
  100. }
  101. if (tree) {
  102. ti = proto_tree_add_item(tree, hfi_json, tvb, 0, -1, ENC_NA);
  103. json_tree = proto_item_add_subtree(ti, ett_json);
  104. if (data_name)
  105. proto_item_append_text(ti, ": %s", data_name);
  106. }
  107. offset = 0;
  108. parser_data.stack = ep_stack_new();
  109. ep_stack_push(parser_data.stack, json_tree);
  110. tt = tvbparse_init(tvb, offset, -1, &parser_data, want_ignore);
  111. /* XXX, only one json in packet? */
  112. while ((tvbparse_get(tt, want)))
  113. ;
  114. offset = tvbparse_curr_offset(tt);
  115. proto_item_set_len(ti, offset);
  116. /* if we have some unparsed data, pass to data-text-lines dissector (?) */
  117. if (tvb_length_remaining(tvb, offset) > 0) {
  118. int datalen, reported_datalen;
  119. tvbuff_t *next_tvb;
  120. datalen = tvb_length_remaining(tvb, offset);
  121. reported_datalen = tvb_reported_length_remaining(tvb, offset);
  122. next_tvb = tvb_new_subset(tvb, offset, datalen, reported_datalen);
  123. call_dissector(text_lines_handle, next_tvb, pinfo, tree);
  124. } else if (data_name) {
  125. col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(%s)", data_name);
  126. }
  127. }
  128. static void before_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
  129. json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
  130. proto_tree *tree = (proto_tree *)ep_stack_peek(data->stack);
  131. proto_tree *subtree;
  132. proto_item *ti;
  133. ti = proto_tree_add_item(tree, &hfi_json_object, tok->tvb, tok->offset, tok->len, ENC_NA);
  134. subtree = proto_item_add_subtree(ti, ett_json_object);
  135. ep_stack_push(data->stack, subtree);
  136. }
  137. static void after_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *elem _U_) {
  138. json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
  139. ep_stack_pop(data->stack);
  140. }
  141. static void before_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
  142. json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
  143. proto_tree *tree = (proto_tree *)ep_stack_peek(data->stack);
  144. proto_tree *subtree;
  145. proto_item *ti;
  146. ti = proto_tree_add_item(tree, &hfi_json_member, tok->tvb, tok->offset, tok->len, ENC_NA);
  147. subtree = proto_item_add_subtree(ti, ett_json_member);
  148. ep_stack_push(data->stack, subtree);
  149. }
  150. static void after_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
  151. json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
  152. proto_tree *tree = (proto_tree *)ep_stack_pop(data->stack);
  153. if (tree) {
  154. tvbparse_elem_t *key_tok = tok->sub;
  155. if (key_tok && key_tok->id == JSON_TOKEN_STRING) {
  156. char *key = tvb_get_ephemeral_string(key_tok->tvb, key_tok->offset, key_tok->len);
  157. proto_item_append_text(tree, " Key: %s", key);
  158. }
  159. /* XXX, &hfi_json_member_key */
  160. }
  161. }
  162. static void before_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
  163. json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
  164. proto_tree *tree = (proto_tree *)ep_stack_peek(data->stack);
  165. proto_tree *subtree;
  166. proto_item *ti;
  167. ti = proto_tree_add_item(tree, &hfi_json_array, tok->tvb, tok->offset, tok->len, ENC_NA);
  168. subtree = proto_item_add_subtree(ti, ett_json_array);
  169. ep_stack_push(data->stack, subtree);
  170. }
  171. static void after_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *elem _U_) {
  172. json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
  173. ep_stack_pop(data->stack);
  174. }
  175. /*
  176. * defines for helping with UTF-16 surrogate pairs
  177. */
  178. #define LEAD_SURROGATE_START 0xd800
  179. #define LEAD_SURROGATE_END 0xdbff
  180. #define TRAIL_SURROGATE_START 0xdc00
  181. #define TRAIL_SURROGATE_END 0xdfff
  182. #define IS_LEAD_SURROGATE(l) (((l)>=LEAD_SURROGATE_START)&&((l)<=LEAD_SURROGATE_END))
  183. #define IS_TRAIL_SURROGATE(t) (((t)>=TRAIL_SURROGATE_START)&&((t)<=TRAIL_SURROGATE_END))
  184. #define GET_UNICHAR_FROM_SURROGATES(l,t) (0x10000+(((l-LEAD_SURROGATE_START)<<10)|(t-TRAIL_SURROGATE_START)))
  185. static char *json_string_unescape(tvbparse_elem_t *tok)
  186. {
  187. char *str = (char *)ep_alloc(tok->len - 1);
  188. int i, j;
  189. j = 0;
  190. for (i = 1; i < tok->len - 1; i++) {
  191. guint8 ch = tvb_get_guint8(tok->tvb, tok->offset + i);
  192. if (ch == '\\') {
  193. i++;
  194. ch = tvb_get_guint8(tok->tvb, tok->offset + i);
  195. switch (ch) {
  196. case '\"':
  197. case '\\':
  198. case '/':
  199. default:
  200. str[j++] = ch;
  201. break;
  202. case 'b':
  203. str[j++] = '\b';
  204. break;
  205. case 'f':
  206. str[j++] = '\f';
  207. break;
  208. case 'n':
  209. str[j++] = '\n';
  210. break;
  211. case 'r':
  212. str[j++] = '\r';
  213. break;
  214. case 't':
  215. str[j++] = '\t';
  216. break;
  217. case 'u':
  218. {
  219. guint32 unicode_hex = 0;
  220. gboolean valid = TRUE;
  221. int k;
  222. for (k = 0; k < 4; k++) {
  223. i++;
  224. unicode_hex <<= 4;
  225. ch = tvb_get_guint8(tok->tvb, tok->offset + i);
  226. if (ch >= '0' && ch <= '9')
  227. unicode_hex |= (ch - '0');
  228. else if (ch >= 'a' && ch <= 'f')
  229. unicode_hex |= (10 + (ch - 'a'));
  230. else if (ch >= 'A' && ch <= 'F')
  231. unicode_hex |= (10 + (ch - 'A'));
  232. else {
  233. valid = FALSE;
  234. break;
  235. }
  236. }
  237. if ((IS_LEAD_SURROGATE(unicode_hex))) {
  238. ch = tvb_get_guint8(tok->tvb, tok->offset + i + 1);
  239. if (ch == '\\') {
  240. i++;
  241. ch = tvb_get_guint8(tok->tvb, tok->offset + i + 1);
  242. if (ch == 'u') {
  243. guint16 lead_surrogate = unicode_hex;
  244. guint16 trail_surrogate = 0;
  245. i++;
  246. for (k = 0; k < 4; k++) {
  247. i++;
  248. trail_surrogate <<= 4;
  249. ch = tvb_get_guint8(tok->tvb, tok->offset + i);
  250. if (ch >= '0' && ch <= '9')
  251. trail_surrogate |= (ch - '0');
  252. else if (ch >= 'a' && ch <= 'f')
  253. trail_surrogate |= (10 + (ch - 'a'));
  254. else if (ch >= 'A' && ch <= 'F')
  255. trail_surrogate |= (10 + (ch - 'A'));
  256. else {
  257. valid = FALSE;
  258. break;
  259. }
  260. }
  261. if ((IS_TRAIL_SURROGATE(trail_surrogate))) {
  262. unicode_hex = GET_UNICHAR_FROM_SURROGATES(lead_surrogate,trail_surrogate);
  263. } else {
  264. valid = FALSE;
  265. }
  266. } else {
  267. valid = FALSE;
  268. }
  269. } else {
  270. valid = FALSE;
  271. }
  272. } else if ((IS_TRAIL_SURROGATE(unicode_hex))) {
  273. i++;
  274. valid = FALSE;
  275. }
  276. if (valid && g_unichar_validate(unicode_hex) && g_unichar_isprint(unicode_hex)) {
  277. /* \uXXXX => 6 bytes */
  278. int charlen = g_unichar_to_utf8(unicode_hex, &str[j]);
  279. j += charlen;
  280. } else
  281. str[j++] = '?';
  282. break;
  283. }
  284. }
  285. } else
  286. str[j++] = ch;
  287. }
  288. str[j] = '\0';
  289. return str;
  290. }
  291. static void after_value(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
  292. json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
  293. proto_tree *tree = (proto_tree *)ep_stack_peek(data->stack);
  294. json_token_type_t value_id = JSON_TOKEN_INVALID;
  295. if (tok->sub)
  296. value_id = (json_token_type_t)tok->sub->id;
  297. switch (value_id) {
  298. case JSON_TOKEN_STRING:
  299. if (tok->len >= 2)
  300. proto_tree_add_unicode_string(tree, hfi_json_value_string.id, tok->tvb, tok->offset, tok->len, json_string_unescape(tok));
  301. else
  302. proto_tree_add_item(tree, &hfi_json_value_string, tok->tvb, tok->offset, tok->len, ENC_ASCII|ENC_NA);
  303. break;
  304. case JSON_TOKEN_NUMBER:
  305. /* XXX, convert to number */
  306. proto_tree_add_item(tree, &hfi_json_value_number, tok->tvb, tok->offset, tok->len, ENC_ASCII|ENC_NA);
  307. break;
  308. case JSON_TOKEN_FALSE:
  309. proto_tree_add_item(tree, &hfi_json_value_false, tok->tvb, tok->offset, tok->len, ENC_NA);
  310. break;
  311. case JSON_TOKEN_NULL:
  312. proto_tree_add_item(tree, &hfi_json_value_null, tok->tvb, tok->offset, tok->len, ENC_NA);
  313. break;
  314. case JSON_TOKEN_TRUE:
  315. proto_tree_add_item(tree, &hfi_json_value_true, tok->tvb, tok->offset, tok->len, ENC_NA);
  316. break;
  317. case JSON_OBJECT:
  318. case JSON_ARRAY:
  319. /* already added */
  320. break;
  321. default:
  322. proto_tree_add_text(tree, tok->tvb, tok->offset, tok->len, "%s", tvb_format_text(tok->tvb, tok->offset, tok->len));
  323. break;
  324. }
  325. }
  326. static void init_json_parser(void) {
  327. static tvbparse_wanted_t _want_object;
  328. static tvbparse_wanted_t _want_array;
  329. tvbparse_wanted_t *want_object, *want_array;
  330. tvbparse_wanted_t *want_member;
  331. tvbparse_wanted_t *want_string;
  332. tvbparse_wanted_t *want_number, *want_int;
  333. tvbparse_wanted_t *want_value;
  334. tvbparse_wanted_t *want_value_separator;
  335. #define tvbparse_optional(id, private_data, before_cb, after_cb, wanted) \
  336. tvbparse_some(id, 0, 1, private_data, before_cb, after_cb, wanted)
  337. tvbparse_wanted_t *want_quot = tvbparse_char(-1,"\"",NULL,NULL,NULL);
  338. want_string = tvbparse_set_seq(JSON_TOKEN_STRING, NULL, NULL, NULL,
  339. want_quot,
  340. tvbparse_some(-1, 0, G_MAXINT, NULL, NULL, NULL,
  341. tvbparse_set_oneof(-1, NULL, NULL, NULL,
  342. tvbparse_not_chars(-1, 0, 0, "\"" "\\", NULL, NULL, NULL), /* XXX, without invalid unicode characters */
  343. tvbparse_set_seq(-1, NULL, NULL, NULL,
  344. tvbparse_char(-1, "\\", NULL, NULL, NULL),
  345. tvbparse_set_oneof(-1, NULL, NULL, NULL,
  346. tvbparse_chars(-1, 0, 1, "\"" "\\" "/bfnrt", NULL, NULL, NULL),
  347. tvbparse_set_seq(-1, NULL, NULL, NULL,
  348. tvbparse_char(-1, "u", NULL, NULL, NULL),
  349. tvbparse_chars(-1, 4, 4, "0123456789abcdefABCDEF", NULL, NULL, NULL),
  350. NULL),
  351. NULL),
  352. NULL),
  353. NULL)
  354. ),
  355. want_quot,
  356. NULL);
  357. want_value_separator = tvbparse_char(-1, ",", NULL, NULL, NULL);
  358. /* int = zero / ( digit1-9 *DIGIT ) */
  359. want_int = tvbparse_set_oneof(-1, NULL, NULL, NULL,
  360. tvbparse_char(-1, "0", NULL, NULL, NULL),
  361. tvbparse_set_seq(-1, NULL, NULL, NULL,
  362. tvbparse_chars(-1, 1, 1, "123456789", NULL, NULL, NULL),
  363. tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */
  364. tvbparse_chars(-1, 0, 0, "0123456789", NULL, NULL, NULL)),
  365. NULL),
  366. NULL);
  367. /* number = [ minus ] int [ frac ] [ exp ] */
  368. want_number = tvbparse_set_seq(JSON_TOKEN_NUMBER, NULL, NULL, NULL,
  369. tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */
  370. tvbparse_chars(-1, 0, 1, "-", NULL, NULL, NULL)),
  371. want_int,
  372. /* frac = decimal-point 1*DIGIT */
  373. tvbparse_optional(-1, NULL, NULL, NULL,
  374. tvbparse_set_seq(-1, NULL, NULL, NULL,
  375. tvbparse_char(-1, ".", NULL, NULL, NULL),
  376. tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL),
  377. NULL)),
  378. /* exp = e [ minus / plus ] 1*DIGIT */
  379. tvbparse_optional(-1, NULL, NULL, NULL,
  380. tvbparse_set_seq(-1, NULL, NULL, NULL,
  381. tvbparse_char(-1, "eE", NULL, NULL, NULL),
  382. tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */
  383. tvbparse_chars(-1, 0, 1, "-+", NULL, NULL, NULL)),
  384. tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL),
  385. NULL)),
  386. NULL);
  387. /* value = false / null / true / object / array / number / string */
  388. want_value = tvbparse_set_oneof(-1, NULL, NULL, after_value,
  389. tvbparse_string(JSON_TOKEN_FALSE, "false", NULL, NULL, NULL),
  390. tvbparse_string(JSON_TOKEN_NULL, "null", NULL, NULL, NULL),
  391. tvbparse_string(JSON_TOKEN_TRUE, "true", NULL, NULL, NULL),
  392. &_want_object,
  393. &_want_array,
  394. want_number,
  395. want_string,
  396. NULL);
  397. /* array = begin-array [ value *( value-separator value ) ] end-array */
  398. want_array = tvbparse_set_seq(JSON_ARRAY, NULL, before_array, after_array,
  399. tvbparse_char(-1, "[", NULL, NULL, NULL),
  400. tvbparse_optional(-1, NULL, NULL, NULL,
  401. tvbparse_set_seq(-1, NULL, NULL, NULL,
  402. want_value,
  403. tvbparse_some(-1, 0, G_MAXINT, NULL, NULL, NULL,
  404. tvbparse_set_seq(-1, NULL, NULL, NULL,
  405. want_value_separator,
  406. want_value,
  407. NULL)),
  408. NULL)
  409. ),
  410. tvbparse_char(-1, "]", NULL, NULL, NULL),
  411. NULL);
  412. _want_array = *want_array;
  413. /* member = string name-separator value */
  414. want_member = tvbparse_set_seq(-1, NULL, before_member, after_member,
  415. want_string,
  416. tvbparse_char(-1, ":", NULL, NULL, NULL),
  417. want_value,
  418. NULL);
  419. /* object = begin-object [ member *( value-separator member ) ] end-object */
  420. want_object = tvbparse_set_seq(JSON_OBJECT, NULL, before_object, after_object,
  421. tvbparse_char(-1, "{", NULL, NULL, NULL),
  422. tvbparse_optional(-1, NULL, NULL, NULL,
  423. tvbparse_set_seq(-1, NULL, NULL, NULL,
  424. want_member,
  425. tvbparse_some(-1, 0, G_MAXINT, NULL, NULL, NULL,
  426. tvbparse_set_seq(-1, NULL, NULL, NULL,
  427. want_value_separator,
  428. want_member,
  429. NULL)),
  430. NULL)
  431. ),
  432. tvbparse_char(-1, "}", NULL, NULL, NULL),
  433. NULL);
  434. _want_object = *want_object;
  435. want_ignore = tvbparse_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL);
  436. /* JSON-text = object / array */
  437. want = tvbparse_set_oneof(-1, NULL, NULL, NULL,
  438. want_object,
  439. want_array,
  440. /* tvbparse_not_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL), */
  441. NULL);
  442. /* XXX, heur? */
  443. }
  444. void
  445. proto_register_json(void) {
  446. static gint *ett[] = {
  447. &ett_json,
  448. &ett_json_array,
  449. &ett_json_object,
  450. &ett_json_member
  451. };
  452. static header_field_info *hfi[] = {
  453. &hfi_json_array,
  454. &hfi_json_object,
  455. &hfi_json_member,
  456. /* &hfi_json_member_key, */
  457. &hfi_json_value_string,
  458. &hfi_json_value_number,
  459. &hfi_json_value_false,
  460. &hfi_json_value_null,
  461. &hfi_json_value_true,
  462. };
  463. int proto_json;
  464. proto_json = proto_register_protocol("JavaScript Object Notation", "JSON", "json");
  465. hfi_json = proto_registrar_get_nth(proto_json);
  466. proto_register_fields(proto_json, hfi, array_length(hfi));
  467. proto_register_subtree_array(ett, array_length(ett));
  468. register_dissector("json", dissect_json, proto_json);
  469. init_json_parser();
  470. }
  471. void
  472. proto_reg_handoff_json(void)
  473. {
  474. dissector_handle_t json_handle;
  475. json_handle = find_dissector("json");
  476. dissector_add_string("media_type", "application/json", json_handle); /* RFC 4627 */
  477. dissector_add_string("media_type", "application/json-rpc", json_handle); /* JSON-RPC over HTTP */
  478. dissector_add_string("media_type", "application/jsonrequest", json_handle); /* JSON-RPC over HTTP */
  479. text_lines_handle = find_dissector("data-text-lines");
  480. }