Skip to content

warren-bank/moz-json-data-view

Repository files navigation

JSON-DataView

Firefox add-on that displays JSON data in a collapsible tree structure with syntax highlights.

Screenshot

JSONP response in Google data feed

Usage

  • the expand (+) and collapse (-) buttons are sensitive to mouse click
    • without any modifier key:
      the action is applied to the selected tree node
    • while pressing any of the following modifier keys: Ctrl or Shift
      the action is applied to the selected tree node,
      as well as recursively to all nodes that descend from the selected tree node

Summary

  • jsonTreeViewer served as a solid starting point for creating a DOM structure from JSON data

    • the original web application is very well coded
    • its core logic has been separated and abstracted into a library
    • enhancements have been gradually added over time
  • highlight.js is used to provide syntax highlighting to the DOM structure

    • specifically, only its css files are used
  • js-beautify is used to add whitespace for readability when syntax highlighting is turned off

    • the JSON text is piped through this library and displayed within a <pre> tag
  • bignumber.js and json-bigint are used to provide an alternate JSON parser

    • this parser provides a way to work around the potential pitfall that:

    • JSON data can specify numeric values that are arbitrarily large

    • the primitive JavaScript number data type has constraints on the possible range of values that it can hold
      ( language limitations are described in detail @ issue #4 )

    • it allows the add-on the ability to retain this fidelity

Detection methodology

  • This add-on will modify the display of all server responses (or local files) that satisfy all of the following criteria:
    • none of the following short-circuit conditions are true:

      • the location protocol is 'view-source:'

      • the location hash contains: No-JSON-DataView

        notes:

        • not case sensitive
        • can be combined with other hash tokens by using one of the separators: /,
    • either:

      • the HTTP header 'content-type' is one of:
        • 'application/json'
        • 'text/json'
        • 'text/x-json'
      • or both must be true:
        • the HTTP header 'content-type' is one of:
          • 'application/javascript'
          • 'application/x-javascript'
          • 'text/javascript'
          • 'text/plain'
        • and one of the following additional conditions are met:
          • the location pathname ends with '.json'
          • the location querystring contains 'callback=', and the response is structured as a JSONP callback function
          • the location hash contains: JSON-DataView

Comments

  • It's become pretty standard practice for jsonp responses to contain javascript comments. The comments serve as a form of protection against an Adobe Flash Player exploit that uses jsonp to bypass the same-origin security policy. This attack is known as Rosetta Flash.

  • When processing the response to determine whether it contains a valid jsonp callback function, the following javascript statements will be ignored:

    • leading and trailing comments (in both // and /* */ formats)
    • leading validation of the callback function, using any of the patterns:
      • cb && cb(json)
      • typeof cb === 'function' && cb(json)

    After the format of the response is validated, the parameter string is extracted from the callback function and treated as a string of JSON data.

  • In the detection methodology, the inspection of the location hash for special control tokens provides a user the added ability to explicitly override the normal detection logic.

    This can be useful in a number of different circumstances. For instance:

    • A web server response is known to contain JSON data; however, the 'content-type' headers are too generic to pass normal detection. This would normally be the result of a misconfigured web server, or poorly written backend script.

      the solution would be to manually append the control token that explicitly signals to the add-on that it should take action: #JSON-DataView

    • Another scenario (that I recently ran into) is when two different add-ons are both triggered to take action on the same page.

      JSON is a very general-purpose way to structure/serialize/transmit data.

      There are many domain specific data formats that are defined by a JSON schema. One such example is the HTTP Archive format.

      If there's an add-on that specifically targets one such format, then whether or not there is the potential for conflict between the two add-ons running at the same time depends on the particular data format.

      • If it has been assigned its own 'content-type' (and if servers tend to use it), then there won't be any conflict.
      • However, if this data format is sent with a generic JSON-ish 'content-type', then both add-ons will most likely be trying to detect the same conditions.

      This is where having the option to manually add control tokens is a very good thing.

      Concrete example:

User Preferences:

  • General Settings

    • Syntax Highlights

      • Enable

      default: true

      • true:
        builds an HTML DOM structure that supports presenting the data within a collapsible tree

      • false:
        filters the JSON data through js-beautify, and outputs into a <pre> DOM element

      • Expand All Nodes

      default: false

      • true:
        during page load, initialize all collapsible tree nodes to an expanded state

      • false:
        during page load, initialize only the root tree node to an expanded state

      • Theme

      default: 'solarized_dark'

      options consist of those provided by highlight.js

    • Optional Features

      • Use non-native JSON parser to support numbers that are too large to represent using primitive JavaScript data types

      default: true

      • Display JSON syntax error when encountered by the JSON parser

      default: true

  • Display: Data Values

    • Strings

      • [false] replace (\n) newline with HTML: <br> tag
      • [false] replace (\t) tab with 4 spaces
      • [true]  replace urls with HTML: <a> tag
      • [true]  escape (\\\) back-slash
      • [false] escape (/\/) forward-slash
      • [true]  escape ("\") double quote
      • [true]  escape (not visible → \r) carriage return
      • [true]  escape (white-space → \n) line feed
      • [true]  escape (white-space → \t) tab
      • [true]  escape (not visible → \f) form feed
      • [true]  escape (not visible → \b) backspace
      • [false] escape (unicode representation → \uNNNN) non-ascii characters
  • Display: Styles

    • CSS

      • font-family

      default: ''

      the (internal) stylesheet assigns a default value.
      this preference is optional;
      if assigned a value, it will override the stylesheet.

      • font-size

      default: 13

      units: px

      • line-height

      default: 2

      units: em

      • padding around the <body>

      default: 1

      units: em

      • width of indentation for expanded children

      default: 1

      units: em

      NOTE:
      1.5em is ADDED to the value specified through this setting.
      This is the width required to ensure the expand/collapse button can be properly displayed.

Examples

URLs to render in-browser after the add-on has been installed, which illustrate its functionality

/**/ hello_world({}); ```

// API callback hello_world({}); ```

hello_world([]) ```

  • https://api.twitter.com/1.1/statuses/user_timeline.json

    • response contains JSON data
    • 'content-type' of response === 'application/json'
  • http://gdata.youtube.com/feeds/api/standardfeeds/most_popular?alt=json&v=2

    • response contains JSON data
    • 'content-type' of response === 'application/json'
  • http://headers.jsontest.com/?mime=1

    • response contains JSON data
    • 'content-type' of response === 'application/json'
  • http://headers.jsontest.com/?mime=2

    • 'content-type' of response === 'application/javascript'
  • http://headers.jsontest.com/?mime=3

    • 'content-type' of response === 'text/javascript'
    • IS NOT acted upon * same work-around methods could be used (as in the earlier example)
  • http://headers.jsontest.com/?mime=4

    • 'content-type' of response === 'text/html'
    • IS NOT acted upon * Anecdotally, it appears that this 'content-type' is a special case. * Under normal circumstances, an add-on is required to register itself to "convert streams" from the incoming 'content-type' values upon which it wishes to act. These "streams" are then (conditionally) "converted" into a 'text/html' request. * It's unclear to me whether the internal logic used by the plugin architecture is that add-ons are invoked only on 'text/html' streams; and that this "stream conversion" API is a methodology by which to allow other streams to enter the workflow. * All that I can say for certain is that the detection methodology doesn't specifically register this add-on to listen for 'text/html' streams, and yet it is invoked during their page-load processing. * This being the case, one of the two aforementioned work-around methods would work: * the presence of a control token in the hash will be seen and obeyed * otherwise, the 'content-type' will fail to match a valid value and the add-on will short-circuit (exit immediately) before the querystring would normally be inspected for a jsonp signature
  • http://headers.jsontest.com/?mime=5

    • 'content-type' of response === 'text/plain'
    • IS NOT acted upon * same work-around methods could be used (as in the earlier example)

License

GPLv3 Copyright (c) 2014, Warren Bank

About

"JSON-DataView" is a Firefox add-on that displays JSON data in a collapsible tree structure with syntax highlights.

Resources

License

Stars

Watchers

Forks

Packages

No packages published