├── LICENSE
├── README.md
├── chrome.manifest
├── chrome
├── locale
│ └── en-US
│ │ └── translations.dtd
└── skin
│ ├── Cu_16.png
│ ├── Cu_24.png
│ ├── Cu_32.png
│ ├── Cu_48.png
│ ├── Cu_64.png
│ ├── Cu_box_256.png
│ ├── classic.css
│ ├── payload_in.png
│ ├── payload_out.png
│ ├── payload_rendered.png
│ ├── renderJSON.css
│ ├── renderLinkFormat.css
│ ├── resource.png
│ ├── resource_circle.png
│ ├── resource_discovery.png
│ ├── resource_home.png
│ ├── resource_key.png
│ ├── resource_link.png
│ ├── resource_observable.png
│ ├── resource_tag.png
│ ├── resource_world.png
│ ├── spinner.gif
│ ├── text_clear.png
│ ├── text_clear_6.png
│ ├── tool_delete.png
│ ├── tool_discover.png
│ ├── tool_get.png
│ ├── tool_observe.png
│ ├── tool_ping.png
│ ├── tool_post.png
│ ├── tool_put.png
│ ├── tool_test.png
│ └── tool_unobserve.png
├── components
└── CoapProtocolHandler.js
├── content
├── DebugOptions.js
├── Handlers.js
├── Helpers.js
├── Launcher.js
├── Logger.js
├── Main.js
├── Observing.js
├── Options.js
├── Plugtest.js
├── Renderers.js
├── ResourceViews.js
├── cbor-js
│ └── cbor.js
├── coap
│ ├── CoapMessage.js
│ ├── CoapRFC7252.js
│ ├── TransactionHandler.js
│ └── UdpClient.js
├── copper.xul
├── launcher.xul
├── namespace.js
├── options.xul
└── overlay.xul
├── defaults
└── preferences
│ └── prefs.js
└── install.rdf
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2016, Institute for Pervasive Computing, ETH Zurich.
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Copper (Cu) CoAP user-agent
2 | ===========================
3 |
4 | Implements [RFC7252](http://tools.ietf.org/html/rfc7252)
5 |
6 | Also see [Copper (Cu4Cr)](https://github.com/mkovatsc/Copper4Cr)
7 |
8 | ## Not supported by Firefox 56+ / WebExtensions API
9 |
10 | Mozilla changed their add-on model to the [WebExtensions API](https://developer.mozilla.org/Add-ons/WebExtensions), which does not allow implementing protocol handlers.
11 |
12 | **Copper cannot be fixed** to work again unless Mozilla changes the internals of Firefox again -- not to the old one, but a safe one that allows for protocol handler add-ons.
13 |
14 | ### Alternatives
15 |
16 | * [Copper4Cr](https://github.com/mkovatsc/Copper4Cr): Chrome also uses the WebExtensions API, but has a loophole through [discontinued Apps](https://blog.chromium.org/2016/08/from-chrome-apps-to-web.html) installed in developer mode
17 | * [Californium (Cf) Browser](https://github.com/eclipse/californium.tools/tree/master/cf-browser): Java-based tool, yet without the debug options support
18 | * [Firefox 55 Portable](https://sourceforge.net/projects/portableapps/files/Mozilla%20Firefox%2C%20Portable%20Ed./Mozilla%20Firefox%2C%20Portable%20Edition%2055.0.3/): Downgrade, but only use for add-ons, not browsing...
19 | 1. Ensure to start offline (no Internet connection!) and disable auto updates
20 | 2. Open `about:config`
21 | 3. Search `browser.tabs.remote.autostart` and `browser.tabs.remote.autostart.2`
22 | 4. Set both to `false`
23 |
24 | ## A Firefox add-on to browse the Internet of Things
25 |
26 | ### How to integrate the Copper sources into Firefox:
27 |
28 | 1. Get the sources from Github: `clone git://github.com/mkovatsc/Copper.git`
29 | 2. Add a text file named `copper@vs.inf.ethz.ch` to your extension directory of your profile:
30 | - Windows: `C:\Users\\AppData\Roaming\Mozilla\Firefox\Profiles\xxxxxxxx.default\extensions\`
31 | - Linux: `~/.mozilla/firefox/xxxxxxxx.default/extensions/`
32 | - MacOS: `~/Library/Application Support/Firefox/Profiles/xxxxxxxx.default/extensions/`
33 | 3. Write the path to the Copper sources (i.e., the directory that contains `install.rdf` and `chrome.manifest`) with (back)slash at the end to the file (e.g., `D:\Projects\Git\Copper\`).
34 | 4. Since Firefox 43 you need to **allow unsigned add-ons** by opening [about:config](about:config) and setting `xpinstall.signatures.required` to false.
35 | 5. Restart Firefox.
36 | 6. Optionally use [about:config](about:config) with the filter "copper" to clean up old configurations.
37 |
38 | Copper should show up in the add-ons list. You can now enter CoAP URIs (e.g., [coap://californium.eclipse.org/](coap://californium.eclipse.org/)) into the address bar and will have a user interface to interact with the CoAP resources on a server. The detailed log output is available through the rectangular button on the top right, next to the preferences button.
39 |
40 | ### See also:
41 |
42 | - [Setting up Extension Development Environment](https://developer.mozilla.org/en/setting_up_extension_development_environment)
43 | - [Firefox Profile Manager](https://support.mozilla.org/en-US/kb/profile-manager-create-and-remove-firefox-profiles)
44 |
45 |
--------------------------------------------------------------------------------
/chrome.manifest:
--------------------------------------------------------------------------------
1 | component {6ffeeb10-91cc-0854-a554-81cf891ced50} components/CoapProtocolHandler.js
2 | contract @mozilla.org/network/protocol;1?name=coap {6ffeeb10-91cc-0854-a554-81cf891ced50}
3 | category profile-after-change CoapProtocolHandler @mozilla.org/network/protocol;1?name=coap
4 |
5 | content copper content/ contentaccessible=yes
6 |
7 | overlay chrome://browser/content/browser.xul content/overlay.xul
8 | overlay chrome://navigator/content/navigator.xul content/overlay.xul
9 |
10 | locale copper en-US chrome/locale/en-US/
11 |
12 | skin copper classic chrome/skin/
13 |
--------------------------------------------------------------------------------
/chrome/locale/en-US/translations.dtd:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/chrome/skin/Cu_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/Cu_16.png
--------------------------------------------------------------------------------
/chrome/skin/Cu_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/Cu_24.png
--------------------------------------------------------------------------------
/chrome/skin/Cu_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/Cu_32.png
--------------------------------------------------------------------------------
/chrome/skin/Cu_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/Cu_48.png
--------------------------------------------------------------------------------
/chrome/skin/Cu_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/Cu_64.png
--------------------------------------------------------------------------------
/chrome/skin/Cu_box_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/Cu_box_256.png
--------------------------------------------------------------------------------
/chrome/skin/classic.css:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2012, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper CoAP browser.
30 | ******************************************************************************/
31 |
32 | toolbar {
33 | margin-bottom: 5px;
34 | border-bottom: 1px solid ThreeDShadow;
35 | -moz-appearance: none;
36 | }
37 |
38 | /* removes lines next to checkboxes (border of empty labels) */
39 | checkbox:focus:not([label]) .checkbox-label-box {
40 | -moz-appearance: none;
41 | border: none;
42 | }
43 |
44 | /* the X button to clear textboxes */
45 | .copper-clear-button {
46 | cursor: default;
47 | opacity: 0.8;
48 |
49 | list-style-image: url('chrome://copper/skin/text_clear_6.png');
50 | padding: 5px 2px 4px 1px;
51 | /*
52 | list-style-image: url('chrome://browser/skin/Toolbar.png');
53 | -moz-image-region: rect(3px 51px 15px 39px);
54 | padding: 2px 0 1px 0;
55 |
56 | list-style-image: url('chrome://browser/skin/reload-stop-go.png');
57 | -moz-image-region: rect(0px 40px 14px 29px);
58 | padding-top:1px;
59 | */
60 | }
61 |
62 | /* default resource icon */
63 | treechildren {
64 | list-style-image: url('chrome://copper/skin/resource_circle.png');
65 | }
66 |
67 | /* special resource icon */
68 | treechildren::-moz-tree-image(host) {
69 | list-style-image: url("chrome://copper/skin/resource_home.png");
70 | }
71 | treechildren::-moz-tree-image(link) {
72 | list-style-image: url("chrome://copper/skin/resource_link.png");
73 | }
74 | treechildren::-moz-tree-image(wellknown) {
75 | list-style-image: url("chrome://copper/skin/resource_world.png");
76 | }
77 | treechildren::-moz-tree-image(discovery) {
78 | list-style-image: url("chrome://copper/skin/resource_discovery.png");
79 | }
80 | treechildren::-moz-tree-image(observable) {
81 | list-style-image: url("chrome://copper/skin/resource_observable.png");
82 | }
83 |
84 | /* resource node appearance */
85 | treechildren::-moz-tree-row() {
86 | height: 24px;
87 | }
88 | treechildren::-moz-tree-cell() {
89 | cursor: pointer;
90 | }
91 | treechildren::-moz-tree-image() {
92 | cursor: pointer;
93 | margin: 0px 4px 0px 2px;
94 | width: 16px;
95 | }
96 | treechildren::-moz-tree-cell-text() {
97 | color: darkgreen;
98 | }
99 | treechildren::-moz-tree-cell-text(hover) {
100 | cursor: pointer;
101 | text-decoration: underline;
102 | }
103 |
104 | treechildren::-moz-tree-indentation() {
105 | width: 20px;
106 | }
107 |
108 | /* highlight current resource */
109 | treechildren::-moz-tree-cell(active) {
110 | background-color: #99CCFF;
111 | }
112 | treechildren::-moz-tree-cell-text(active) {
113 | font-weight: bold;
114 | color: black;
115 | }
116 | treechildren::-moz-tree-cell-text(cached) {
117 | color: black;
118 | }
119 |
--------------------------------------------------------------------------------
/chrome/skin/payload_in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/payload_in.png
--------------------------------------------------------------------------------
/chrome/skin/payload_out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/payload_out.png
--------------------------------------------------------------------------------
/chrome/skin/payload_rendered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/payload_rendered.png
--------------------------------------------------------------------------------
/chrome/skin/renderJSON.css:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2012, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper CoAP browser.
30 | ******************************************************************************/
31 |
32 | .json-content li {
33 | list-style-type: none;
34 | }
35 |
36 | /* Containers */
37 |
38 | .json-content .label {
39 | margin: 0px;
40 | font-weight: bold;
41 | }
42 |
43 | .json-content .object {
44 | padding-left: 20px;
45 | margin: 5px 0px 5px 0px;
46 | }
47 | .json-content .object:before {
48 | font-weight: bold;
49 | margin-left: -20px;
50 | content: '{';
51 | }
52 | .json-content .object:after {
53 | font-weight: bold;
54 | margin-left: -20px;
55 | content: '}';
56 | }
57 |
58 | .json-content .array {
59 | padding-left: 20px;
60 | margin: 5px 0px 5px 0px;
61 | }
62 | .json-content .array:before {
63 | font-weight: bold;
64 | margin-left: -20px;
65 | content: '[';
66 | }
67 | .json-content .array:after {
68 | font-weight: bold;
69 | margin-left: -20px;
70 | content: ']';
71 | }
72 |
73 | /* Types */
74 | .json-content .value {
75 | }
76 |
77 | .json-content .string {
78 | color: green;
79 | white-space: pre;
80 | }
81 |
82 | .json-content .null {
83 | color: black;
84 | font-weight: bold;
85 | }
86 |
87 | .json-content .int {
88 | color: red;
89 | }
90 |
91 | .json-content .float {
92 | color: purple;
93 | }
94 |
95 | .json-content .bool {
96 | color: blue;
97 | }
98 |
--------------------------------------------------------------------------------
/chrome/skin/renderLinkFormat.css:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2012, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper CoAP browser.
30 | ******************************************************************************/
31 |
32 | .link-content ul {
33 | list-style-type: none;
34 | }
35 |
36 | .link-content .uri {
37 | font-size: 16px;
38 | font-weight: bold;
39 | margin-left: -20px;
40 | }
41 |
42 | /* Containers */
43 |
44 | .link-content .object {
45 | list-style-type: square;
46 | padding-left: 20px;
47 | margin: 5px 0px 5px 0px;
48 | }
49 |
50 | .link-content .array {
51 | list-style-type: circle;
52 | padding-left: 20px;
53 | margin: 5px 0px 5px 0px;
54 | color: black;
55 | }
56 | .link-content .array:before {
57 | font-weight: bold;
58 | margin-top: -20px;
59 | }
60 |
61 | /* Types */
62 | .link-content .value {
63 | }
64 |
65 | .link-content .string {
66 | color: green;
67 | white-space: pre;
68 | }
69 |
70 | .link-content .null {
71 | color: black;
72 | font-weight: bold;
73 | }
74 |
75 | .link-content .int {
76 | color: red;
77 | }
78 |
79 | .link-content .float {
80 | color: purple;
81 | }
82 |
83 | .link-content .bool {
84 | color: blue;
85 | }
86 |
87 |
88 |
89 | .link-content .label {
90 | margin: 0px;
91 | font-weight: bold;
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/chrome/skin/resource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource.png
--------------------------------------------------------------------------------
/chrome/skin/resource_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource_circle.png
--------------------------------------------------------------------------------
/chrome/skin/resource_discovery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource_discovery.png
--------------------------------------------------------------------------------
/chrome/skin/resource_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource_home.png
--------------------------------------------------------------------------------
/chrome/skin/resource_key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource_key.png
--------------------------------------------------------------------------------
/chrome/skin/resource_link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource_link.png
--------------------------------------------------------------------------------
/chrome/skin/resource_observable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource_observable.png
--------------------------------------------------------------------------------
/chrome/skin/resource_tag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource_tag.png
--------------------------------------------------------------------------------
/chrome/skin/resource_world.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/resource_world.png
--------------------------------------------------------------------------------
/chrome/skin/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/spinner.gif
--------------------------------------------------------------------------------
/chrome/skin/text_clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/text_clear.png
--------------------------------------------------------------------------------
/chrome/skin/text_clear_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/text_clear_6.png
--------------------------------------------------------------------------------
/chrome/skin/tool_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_delete.png
--------------------------------------------------------------------------------
/chrome/skin/tool_discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_discover.png
--------------------------------------------------------------------------------
/chrome/skin/tool_get.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_get.png
--------------------------------------------------------------------------------
/chrome/skin/tool_observe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_observe.png
--------------------------------------------------------------------------------
/chrome/skin/tool_ping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_ping.png
--------------------------------------------------------------------------------
/chrome/skin/tool_post.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_post.png
--------------------------------------------------------------------------------
/chrome/skin/tool_put.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_put.png
--------------------------------------------------------------------------------
/chrome/skin/tool_test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_test.png
--------------------------------------------------------------------------------
/chrome/skin/tool_unobserve.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkovatsc/Copper/f3cd8d5a22aadaefcd8e316470f3d837ea7a66ab/chrome/skin/tool_unobserve.png
--------------------------------------------------------------------------------
/components/CoapProtocolHandler.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2016, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Firefox protocol handler for 'coap:'
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | /**
39 | * CopperProtocolHandler namespace.
40 | */
41 | if ("undefined" == typeof(CopperProtocol)) {
42 | var CopperProtocol = {};
43 | };
44 |
45 | // Array allows for multiple schemes (e.g., coap and coaps for coap with DTLS)
46 | CopperProtocol.__defineGetter__("CLASS_ID", function() { return [Components.ID('{6ffeeb10-91cc-0854-a554-81cf891ced50}')]; });
47 | CopperProtocol.__defineGetter__("CLASS_SCHEME", function() { return ['coap']; });
48 | CopperProtocol.__defineGetter__("CLASS_DEFAULT_PORT", function() { return [-1]; });
49 | CopperProtocol.__defineGetter__("CLASS_FLAGS", function() { return [Components.interfaces.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE]; });
50 | CopperProtocol.__defineGetter__("CLASS_NAME", function() { return ['CoAP (RFC 7252)']; });
51 |
52 | CopperProtocol.__defineGetter__("SECURITY", function() { return Components.interfaces.nsILoadInfo.SEC_SANDBOXED | Components.interfaces.nsILoadInfo.SEC_ALLOW_CHROME; });
53 |
54 | /**
55 | * Handles the CoAP protocol
56 | */
57 | CopperProtocol.Handler = function() {};
58 |
59 | CopperProtocol.Handler.prototype = {
60 |
61 | defaultPort : CopperProtocol.CLASS_DEFAULT_PORT[0],
62 | protocolFlags : CopperProtocol.CLASS_FLAGS[0],
63 | scheme: CopperProtocol.CLASS_SCHEME[0],
64 |
65 | allowPort: function(port, scheme) {
66 | return false;
67 | },
68 |
69 | newURI : function(aSpec, aCharset, aBaseURI) {
70 |
71 | /*
72 | * Standard URL with URLTYPE_AUTHORITY = 2
73 | *
74 | * blah:foo/bar => blah://foo/bar
75 | * blah:/foo/bar => blah://foo/bar
76 | * blah://foo/bar => blah://foo/bar
77 | * blah:///foo/bar => blah://foo/bar
78 | */
79 |
80 | try {
81 | var uri = Components.classes["@mozilla.org/network/standard-url;1"].createInstance(Components.interfaces.nsIStandardURL);
82 | uri.init(Components.interfaces.nsIStandardURL.URLTYPE_AUTHORITY, this.defaultPort, aSpec, aCharset, aBaseURI);
83 |
84 | return uri;
85 |
86 | } catch (ex) {
87 | // will cause an alert
88 | return uri = Components.classes["@mozilla.org/network/simple-uri;1"].createInstance(Components.interfaces.nsIURI);
89 | }
90 | },
91 |
92 | newChannel : function(aURI) {
93 | var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
94 | return ioService.newChannel2("chrome://copper/content/copper.xul", null, null, null, null, null, CopperProtocol.SECURITY, null);
95 | },
96 |
97 | /**
98 | * The QueryInterface method provides runtime type discovery.
99 | * More: http://developer.mozilla.org/en/docs/nsISupports
100 | * @param aIID the IID of the requested interface.
101 | * @return the resulting interface pointer.
102 | */
103 | QueryInterface : function(aIID) {
104 | if (!aIID.equals(Components.interfaces.nsIProtocolHandler) && !aIID.equals(Components.interfaces.nsISupports)) {
105 | throw Components.results.NS_ERROR_NO_INTERFACE;
106 | }
107 | return this;
108 | }
109 |
110 | };
111 |
112 | /**
113 | * The nsIFactory interface allows for the creation of nsISupports derived
114 | * classes without specifying a concrete class type.
115 | * More: http://developer.mozilla.org/en/docs/nsIFactory
116 | */
117 | CopperProtocol.HandlerFactory = function() {};
118 |
119 | CopperProtocol.HandlerFactory.prototype = {
120 | createInstance: function (aOuter, aIID) {
121 | if (null != aOuter) {
122 | throw Components.results.NS_ERROR_NO_AGGREGATION;
123 | }
124 | return (new CopperProtocol.Handler()).QueryInterface(aIID);
125 | }
126 | };
127 |
128 | /**
129 | * Firefox 3.x
130 | * The nsIModule interface must be implemented by each XPCOM component. It is
131 | * the main entry point by which the system accesses an XPCOM component.
132 | * More: http://developer.mozilla.org/en/docs/nsIModule
133 | */
134 | CopperProtocol.HandlerModule = {
135 | /**
136 | * When the nsIModule is discovered, this method will be called so that any
137 | * setup registration can be preformed.
138 | * @param aCompMgr the global component manager.
139 | * @param aLocation the location of the nsIModule on disk.
140 | * @param aLoaderStr opaque loader specific string.
141 | * @param aType loader type being used to load this module.
142 | */
143 | registerSelf : function(aCompMgr, aLocation, aLoaderStr, aType) {
144 | aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
145 | for (var i in CopperProtocol.CLASS_SCHEME) {
146 | aCompMgr.registerFactoryLocation(CopperProtocol.CLASS_ID[i], CopperProtocol.CLASS_NAME[i], "@mozilla.org/network/protocol;1?name="+CopperProtocol.CLASS_SCHEME[i], aLocation, aLoaderStr, aType);
147 | }
148 | },
149 |
150 | /**
151 | * When the nsIModule is being unregistered, this method will be called so
152 | * that any cleanup can be preformed.
153 | * @param aCompMgr the global component manager.
154 | * @param aLocation the location of the nsIModule on disk.
155 | * @param aLoaderStr opaque loader specific string.
156 | */
157 | unregisterSelf : function (aCompMgr, aLocation, aLoaderStr) {
158 | aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
159 | for (var i in CopperProtocol.CLASS_SCHEME) {
160 | aCompMgr.unregisterFactoryLocation(CopperProtocol.CLASS_ID[i], aLocation);
161 | }
162 | },
163 |
164 | /**
165 | * This method returns a class object for a given ClassID and IID.
166 | * @param aCompMgr the global component manager.
167 | * @param aClass the ClassID of the object instance requested.
168 | * @param aIID the IID of the object instance requested.
169 | * @return the resulting interface pointer.
170 | * @throws NS_ERROR_NOT_IMPLEMENTED if aIID is inadequate.
171 | * @throws NS_ERROR_NO_INTERFACE if the interface is not found.
172 | */
173 | getClassObject : function(aCompMgr, aClass, aIID) {
174 | if (!aIID.equals(Components.interfaces.nsIFactory)) {
175 | throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
176 | }
177 |
178 | if (aClass.equals(CopperProtocol.CLASS_ID[0])) {
179 | return new CopperProtocol.HandlerFactory();
180 | }
181 |
182 | throw Components.results.NS_ERROR_NO_INTERFACE;
183 | },
184 |
185 | /**
186 | * This method may be queried to determine whether or not the component
187 | * module can be unloaded by XPCOM.
188 | * @param aCompMgr the global component manager.
189 | * @return true if the module can be unloaded by XPCOM. false otherwise.
190 | */
191 | canUnload: function(aCompMgr) {
192 | return true;
193 | }
194 | };
195 |
196 | /**
197 | * Initial entry point Firefox 3.x
198 | * @param aCompMgr the global component manager.
199 | * @param aFileSpec component file.
200 | * @return the module for the service.
201 | */
202 | function NSGetModule(aCompMgr, aFileSpec) {
203 | return CopperProtocol.HandlerModule;
204 | }
205 |
206 | /**
207 | * Initial entry point Firefox 4
208 | * @param cid the class ID from the manifest.
209 | * @return the module for the service.
210 | */
211 | function NSGetFactory (cid) {
212 | for(var i in CopperProtocol.CLASS_ID) {
213 | if (cid.equals(CopperProtocol.CLASS_ID[0])) {
214 | return new CopperProtocol.HandlerFactory();
215 | }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/content/DebugOptions.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Debug options sidebar functions
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | // Debug options functions
39 | ////////////////////////////////////////////////////////////////////////////////
40 |
41 | Copper.initDebugContentFormats = function() {
42 | for (var i = 0; i<100; ++i) {
43 | var name = '';
44 | if ( (name = Copper.getContentFormatName(i))!='unknown/unknown') {
45 |
46 | var menuitem1 = document.createElement('menuitem');
47 | var menuitem2 = document.createElement('menuitem');
48 |
49 | menuitem1.setAttribute('label', Copper.getContentFormatName(i));
50 | menuitem1.setAttribute('value', i);
51 | menuitem2.setAttribute('label', Copper.getContentFormatName(i));
52 | menuitem2.setAttribute('value', i);
53 |
54 | document.getElementById('popup_content_types').appendChild(menuitem1);
55 | document.getElementById('popup_accepts').appendChild(menuitem2);
56 | }
57 | }
58 | };
59 |
60 | Copper.loadDebugOptions = function() {
61 | document.getElementById('chk_debug_options').checked = Copper.prefManager.getBoolPref('extensions.copper.debug.options-enabled');
62 | document.getElementById('debug_option_content_format').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.content-format');
63 | document.getElementById('debug_option_max_age').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.max-age');
64 | document.getElementById('debug_option_proxy_uri').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.proxy-uri');
65 | document.getElementById('debug_option_proxy_scheme').checked = Copper.prefManager.getBoolPref('extensions.copper.debug.options.proxy-scheme');
66 | document.getElementById('debug_option_etag').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.etag');
67 | document.getElementById('debug_option_uri_host').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.uri-host');
68 | document.getElementById('debug_option_location_path').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.location-path');
69 | document.getElementById('debug_option_uri_port').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.uri-port');
70 | document.getElementById('debug_option_location_query').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.location-query');
71 | document.getElementById('debug_option_observe').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.observe');
72 | document.getElementById('debug_option_token').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.token');
73 | document.getElementById('debug_option_accept').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.accept');
74 | document.getElementById('debug_option_if_match').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.if-match');
75 | document.getElementById('debug_option_block2').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.block2');
76 | document.getElementById('debug_option_block1').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.block1');
77 | document.getElementById('debug_option_size2').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.size2');
78 | document.getElementById('debug_option_size1').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.size1');
79 | document.getElementById('chk_debug_option_block_auto').checked = Copper.prefManager.getBoolPref('extensions.copper.debug.options.block-auto');
80 | document.getElementById('debug_option_if_none_match').checked = Copper.prefManager.getBoolPref('extensions.copper.debug.options.if-none-match');
81 |
82 | document.getElementById('debug_option_custom_number').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.custom-number');
83 | document.getElementById('debug_option_custom_value').value = Copper.prefManager.getCharPref('extensions.copper.debug.options.custom-value');
84 | };
85 |
86 | Copper.saveDebugOptions = function() {
87 | Copper.prefManager.setBoolPref('extensions.copper.debug.options-enabled', document.getElementById('chk_debug_options').checked);
88 | Copper.prefManager.setCharPref('extensions.copper.debug.options.content-format', document.getElementById('debug_option_content_format').value);
89 | Copper.prefManager.setCharPref('extensions.copper.debug.options.max-age', document.getElementById('debug_option_max_age').value);
90 | Copper.prefManager.setCharPref('extensions.copper.debug.options.proxy-uri', document.getElementById('debug_option_proxy_uri').value);
91 | Copper.prefManager.setBoolPref('extensions.copper.debug.options.proxy-scheme', document.getElementById('debug_option_proxy_scheme').checked);
92 | Copper.prefManager.setCharPref('extensions.copper.debug.options.etag', document.getElementById('debug_option_etag').value);
93 | Copper.prefManager.setCharPref('extensions.copper.debug.options.uri-host', document.getElementById('debug_option_uri_host').value);
94 | Copper.prefManager.setCharPref('extensions.copper.debug.options.location-path', document.getElementById('debug_option_location_path').value);
95 | Copper.prefManager.setCharPref('extensions.copper.debug.options.uri-port', document.getElementById('debug_option_uri_port').value);
96 | Copper.prefManager.setCharPref('extensions.copper.debug.options.location-query', document.getElementById('debug_option_location_query').value);
97 | Copper.prefManager.setCharPref('extensions.copper.debug.options.observe', document.getElementById('debug_option_observe').value);
98 | Copper.prefManager.setCharPref('extensions.copper.debug.options.token', document.getElementById('debug_option_token').value);
99 | Copper.prefManager.setCharPref('extensions.copper.debug.options.accept', document.getElementById('debug_option_accept').value);
100 | Copper.prefManager.setCharPref('extensions.copper.debug.options.if-match', document.getElementById('debug_option_if_match').value);
101 | Copper.prefManager.setCharPref('extensions.copper.debug.options.block2', document.getElementById('debug_option_block2').value);
102 | Copper.prefManager.setCharPref('extensions.copper.debug.options.block1', document.getElementById('debug_option_block1').value);
103 | Copper.prefManager.setCharPref('extensions.copper.debug.options.size2', document.getElementById('debug_option_size2').value);
104 | Copper.prefManager.setCharPref('extensions.copper.debug.options.size1', document.getElementById('debug_option_size1').value);
105 | Copper.prefManager.setBoolPref('extensions.copper.debug.options.block-auto', document.getElementById('chk_debug_option_block_auto').checked);
106 | Copper.prefManager.setBoolPref('extensions.copper.debug.options.if-none-match', document.getElementById('debug_option_if_none_match').checked);
107 |
108 | Copper.prefManager.setCharPref('extensions.copper.debug.options.custom-number', document.getElementById('debug_option_custom_number').value);
109 | Copper.prefManager.setCharPref('extensions.copper.debug.options.custom-value', document.getElementById('debug_option_custom_value').value);
110 | };
111 |
112 | Copper.resetDebugOptions = function() {
113 |
114 | var list = document.getElementById('sidebar').getElementsByTagName('image');
115 | for (var i=0; i "http:"
156 | // parser.hostname; // => "example.com"
157 | // parser.port; // => "3000"
158 | // parser.pathname; // => "/pathname/"
159 | // parser.search; // => "?search=test"
160 | // parser.hash; // => "#hash"
161 | // parser.host; // => "example.com:3000"
162 |
163 | message.setProxyScheme(uri.protocol.slice(0, -1));
164 | message.setUriHost(uri.hostname);
165 | if (uri.port != '') message.setUriPort(uri.port);
166 | message.setUri(uri.pathname.substr(1) + uri.search);
167 |
168 | } else {
169 | message.setProxyUri(document.getElementById('debug_option_proxy_uri').value);
170 | }
171 | }
172 |
173 | if (document.getElementById('debug_option_etag').value != '') {
174 | message.setETag(document.getElementById('debug_option_etag').value);
175 | }
176 | if (document.getElementById('debug_option_uri_host').value != '') {
177 | message.setUriHost(document.getElementById('debug_option_uri_host').value);
178 | }
179 | if (document.getElementById('debug_option_location_path').value != '') {
180 | message.setLocationPath(document.getElementById('debug_option_location_path').value);
181 | }
182 |
183 | if (document.getElementById('debug_option_uri_port').value != '') {
184 | message.setUriPort(parseInt(document.getElementById('debug_option_uri_port').value));
185 | }
186 |
187 | if (document.getElementById('debug_option_location_query').value != '') {
188 | message.setLocationQuery(document.getElementById('debug_option_location_query').value);
189 | }
190 |
191 | if (document.getElementById('debug_option_observe').value != '') {
192 | message.setObserve(parseInt(document.getElementById('debug_option_observe').value));
193 | }
194 | if (document.getElementById('debug_option_token').value != '') {
195 | message.setToken(document.getElementById('debug_option_token').value);
196 | }
197 |
198 | if (document.getElementById('debug_option_accept').value != '') {
199 | if (document.getElementById('debug_option_accept').selectedItem) {
200 | message.setAccept(parseInt(document.getElementById('debug_option_accept').selectedItem.value));
201 | } else {
202 | message.setAccept(parseInt(document.getElementById('debug_option_accept').value));
203 | }
204 | }
205 |
206 | if (document.getElementById('debug_option_if_match').value != '') {
207 | message.setIfMatch(document.getElementById('debug_option_if_match').value);
208 | }
209 |
210 | if (Copper.behavior.blockSize != 0 && document.getElementById('debug_option_block2').value != '') {
211 | message.setBlock2(parseInt(document.getElementById('debug_option_block2').value), Copper.behavior.blockSize);
212 | }
213 |
214 | if (Copper.behavior.blockSize != 0 && document.getElementById('debug_option_block1').value != '') {
215 | message.setBlock1(parseInt(document.getElementById('debug_option_block1').value), Copper.behavior.blockSize, document
216 | .getElementById('debug_option_block1').value.match(/\+/));
217 | }
218 |
219 | if (document.getElementById('debug_option_size2').value != '') {
220 | message.setSize2(parseInt(document.getElementById('debug_option_size2').value));
221 | }
222 |
223 | if (document.getElementById('debug_option_size1').value != '' && !Copper.behavior.sendSize1) {
224 | message.setSize1(parseInt(document.getElementById('debug_option_size1').value));
225 | }
226 |
227 | if (Copper.OPTION_IF_NONE_MATCH && document.getElementById('debug_option_if_none_match').checked) {
228 | message.setIfNoneMatch();
229 | }
230 |
231 | if (document.getElementById('debug_option_custom_number').value != '') {
232 | message.setCustom(document.getElementById('debug_option_custom_number').value, document.getElementById('debug_option_custom_value').value);
233 | }
234 | }
235 | } catch (ex) {
236 | Copper.logError(ex);
237 | }
238 | };
239 |
--------------------------------------------------------------------------------
/content/Handlers.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Message handler functions
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | // CoAP message handlers
39 | ////////////////////////////////////////////////////////////////////////////////
40 |
41 | // Handle normal incoming messages, registered as default at TransactionHandler
42 | Copper.defaultHandler = function(message) {
43 |
44 | Copper.logEvent('INFO: defaultHandler()');
45 |
46 | // late blocksize negotiation
47 | if (message.isOption(Copper.OPTION_BLOCK2) && Copper.downloadMethod!=0
48 | || message.isOption(Copper.OPTION_BLOCK1) && Copper.uploadMethod!=0) {
49 | return Copper.blockwiseHandler(message);
50 | }
51 |
52 | Copper.displayMessageInfo(message);
53 | Copper.displayPayload(message);
54 |
55 | if (message.getRTT) Copper.updateLabel('info_code', ' (RTT ' + message.getRTT() + ' ms)', true);
56 |
57 | if (message.getContentFormat()==Copper.CONTENT_TYPE_APPLICATION_LINK_FORMAT) {
58 | Copper.updateResourceLinks( Copper.parseLinkFormat( document.getElementById('packet_payload').value ) );
59 | }
60 | };
61 |
62 | //Handle ping responses
63 | Copper.pingHandler = function(message) {
64 | Copper.logEvent('INFO: pingHandler()');
65 |
66 | Copper.displayMessageInfo(message);
67 | Copper.updateLabel('info_code', 'Pong: Remote responds to CoAP');
68 | if (message.getRTT) Copper.updateLabel('info_code', ' (RTT ' + message.getRTT() + ' ms)', true);
69 | };
70 |
71 | // Handle messages with block-wise transfer
72 | Copper.blockwiseHandler = function(message) {
73 | Copper.logEvent('INFO: blockwiseHandler()');
74 |
75 | Copper.displayMessageInfo(message);
76 | Copper.updateLabel('info_code', ' (Blockwise)', true); // call after displayMessageInfo()
77 | Copper.displayPayload(message);
78 |
79 | if (message.isOption(Copper.OPTION_BLOCK1)) {
80 |
81 | // block size negotiation
82 | let size = message.getBlock1Size();
83 | if (Copper.behavior.blockSize!=0 && Copper.behavior.blockSize < size) {
84 | size = Copper.behavior.blockSize;
85 | }
86 | // calculate offset first to continue with correct num (if block size differs)
87 | let offset = message.getBlock1Size() * (message.getBlock1Number() + 1);
88 | let num = offset/size;
89 |
90 | if (message.isSuccess() && Copper.uploadBlocks!=null && offset < Copper.uploadBlocks.length) {
91 |
92 | Copper.updateLabel('info_code', ' (Uploading...)', true);
93 |
94 | // automatically count up
95 | document.getElementById('debug_option_block1').value = num;
96 | if (offset+size < Copper.uploadBlocks.length) document.getElementById('debug_option_block1').value += '+';
97 |
98 | if ( !document.getElementById('chk_debug_options').checked || document.getElementById('chk_debug_option_block_auto').checked ) {
99 | Copper.sendBlockwise1(Copper.mainWindow.document.getElementById('urlbar').value, num, size);
100 | return;
101 | }
102 | } else {
103 | // finished
104 | Copper.uploadMethod = 0;
105 | Copper.uploadBlocks = null;
106 | document.getElementById('debug_option_block1').value = ''; // important when continuing with Block1
107 |
108 | Copper.updateLabel('info_code', ' (Upload finished)', true); // call after displayMessageInfo()
109 |
110 | // call custom callback
111 | if (Copper.uploadHandler) {
112 | Copper.uploadHandler(message);
113 | Copper.uploadHandler = null;
114 | }
115 | }
116 | }
117 |
118 | if (message.isOption(Copper.OPTION_BLOCK2)) {
119 | if (message.getBlock2More()) {
120 |
121 | // block size negotiation
122 | let size = Copper.negotiateBlockSize(message);
123 | let offset = message.getBlock2Offset();
124 | let num = offset/size;
125 |
126 | // automatically count up
127 | document.getElementById('debug_option_block2').value = num;
128 |
129 | if ( !document.getElementById('chk_debug_options').checked || document.getElementById('chk_debug_option_block_auto').checked) {
130 | Copper.sendBlockwise2(Copper.mainWindow.document.getElementById('urlbar').value, num, size);
131 | }
132 | } else {
133 | // finished
134 | Copper.downloadMethod = 0;
135 | document.getElementById('debug_option_block2').value = '';
136 |
137 | Copper.updateLabel('info_code', ' (Download finished)', true); // call after displayMessageInfo()
138 |
139 | if (message.getContentFormat()==Copper.CONTENT_TYPE_APPLICATION_LINK_FORMAT) {
140 | Copper.updateResourceLinks( Copper.parseLinkFormat( document.getElementById('packet_payload').value ) );
141 | }
142 |
143 | // call custom callback
144 | if (Copper.downloadHandler) {
145 | Copper.downloadHandler(message);
146 | Copper.downloadHandler = null;
147 | }
148 | }
149 | }
150 |
151 | };
152 |
153 | //Handle messages with block-wise transfer
154 | Copper.observingHandler = function(message) {
155 | Copper.logEvent('INFO: observingHandler()');
156 |
157 | Copper.displayMessageInfo(message);
158 | if (message.isOption(Copper.OPTION_OBSERVE)) {
159 | Copper.updateLabel('info_code', ' (Observing)', true); // call after displayMessageInfo()
160 | } else {
161 | Copper.updateLabel('info_code', ' (Observing stopped)', true); // call after displayMessageInfo()
162 | }
163 | Copper.displayPayload(message);
164 |
165 | //TODO duplicated code from blockwise handler
166 | if (message.isOption(Copper.OPTION_BLOCK2)) {
167 |
168 | Copper.updateLabel('info_code', ' (Blockwise)', true); // call after displayMessageInfo()
169 |
170 | if (message.getBlock2More()) {
171 |
172 | Copper.downloadMethod = Copper.GET;
173 |
174 | // block size negotiation
175 | let size = Copper.negotiateBlockSize(message);
176 | let offset = message.getBlock2Offset();
177 | let num = offset/size;
178 |
179 | Copper.sendBlockwise2(Copper.mainWindow.document.getElementById('urlbar').value, num, size);
180 | }
181 | }
182 | };
183 |
184 | // Handle messages with link format payload
185 | Copper.discoverCache = new String();
186 | Copper.discoverHandler = function(message) {
187 |
188 | Copper.logEvent('INFO: discoverHandler()');
189 |
190 | if (message.getCode()!=Copper.CODE_2_05_CONTENT) return;
191 |
192 | if (message.getContentFormat()==Copper.CONTENT_TYPE_APPLICATION_LINK_FORMAT) {
193 |
194 | Copper.updateLabel('info_code', 'Discovering');
195 |
196 | if (message.isOption(Copper.OPTION_BLOCK2)) {
197 |
198 | if (message.getBlock2More()) {
199 |
200 | // block size negotiation
201 | let size = Copper.negotiateBlockSize(message);
202 | let offset = message.getBlock2Offset();
203 | let num = offset/size;
204 | Copper.discover(num, size);
205 | }
206 |
207 | if (message.getBlock2Number()==0) {
208 | Copper.logEvent('INFO: Starting new discover cache');
209 | Copper.discoverCache = new String();
210 | }
211 |
212 | Copper.discoverCache += Copper.bytes2str( message.getPayload() );
213 |
214 | if (!message.getBlock2More()) {
215 | Copper.logEvent('INFO: Appending discover cache');
216 | // link-format
217 | Copper.resourcesCached = false;
218 | Copper.updateResourceLinks( Copper.parseLinkFormat( Copper.discoverCache ) );
219 |
220 | document.getElementById('toolbar_discover').image = 'chrome://copper/skin/tool_discover.png';
221 | }
222 | } else {
223 | // link-format
224 | Copper.resourcesCached = false;
225 | Copper.updateResourceLinks( Copper.parseLinkFormat( Copper.bytes2str( message.getPayload() ) ) );
226 |
227 | document.getElementById('toolbar_discover').image = 'chrome://copper/skin/tool_discover.png';
228 | }
229 | } else {
230 | Copper.logWarning(new Error("Discovery requires 'application/link-format', but received "+message.getContentFormat()));
231 | }
232 | };
233 |
234 | Copper.errorHandler = function(message) {
235 | Copper.logEvent('INFO: errorHandler()');
236 |
237 | document.getElementById('group_head').setAttribute('style', 'display: none;');
238 | document.getElementById('group_payload').setAttribute('style', 'display: none;');
239 |
240 | Copper.updateLabel('info_code', message.getCopperCode());
241 |
242 | Copper.endpoint.cancelTransactions();
243 | };
244 |
--------------------------------------------------------------------------------
/content/Launcher.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2016, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Main program code for the Copper CoAP Browser
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | Copper.check = function() {
39 |
40 | var firstRun = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch).getBoolPref('extensions.copper.first-run');
41 |
42 | if (firstRun) {
43 |
44 | let id = 'copper-toolbar-button';
45 |
46 | // install the Cu toolbar button for the launcher
47 | if (!document.getElementById(id)) {
48 | var toolbar = document.getElementById('addon-bar');
49 |
50 | toolbar.insertItem(id);
51 | toolbar.setAttribute("currentset", toolbar.currentSet);
52 | document.persist(toolbar.id, "currentset");
53 |
54 | toolbar.collapsed = false;
55 | }
56 |
57 | // set first-run to false
58 | Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch).setBoolPref('extensions.copper.first-run', false);
59 | }
60 | };
61 |
62 | Copper.hideLauncher = function() {
63 |
64 | let id = 'copper-toolbar-button';
65 |
66 | if (document.getElementById(id)) {
67 | var toolbar = document.getElementById('addon-bar');
68 |
69 | let newSet = toolbar.currentSet.replace(/(,copper-toolbar-button|copper-toolbar-button,)/, '');
70 | toolbar.setAttribute("currentset", newSet);
71 | document.persist(toolbar.id, "currentset");
72 | }
73 |
74 | Copper.firstRun = false;
75 | };
76 |
77 | Copper.launch = function() {
78 | window.openDialog('chrome://copper/content/launcher.xul', 'Launcher', 'chrome,titlebar,toolbar,centerscreen,modal');
79 | Copper.hideLauncher();
80 | document.getElementById('urlbar').focus();
81 | };
82 |
83 | addEventListener("load", Copper.check, false);
84 |
--------------------------------------------------------------------------------
/content/Logger.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2015, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | *******************************************************************************/
31 | /**
32 | * \file Main script file for the LWM2M DevKit.
33 | *
34 | * \author Matthias Kovatsch
35 | */
36 |
37 | Copper.operationLog = [];
38 | Copper.operationReportingLog = [];
39 |
40 | Copper.resetLogger = function() {
41 | let rows = document.getElementById('log_messages');
42 | let toRemove = rows.getElementsByTagName('listitem');
43 | for (let r in toRemove) {
44 | try {rows.removeChild(toRemove[r]);} catch (ex) {};
45 | }
46 | };
47 |
48 | Copper.logMessage = function(message, out) {
49 |
50 | let rows = document.getElementById('log_messages');
51 |
52 | var item = document.createElement('listitem');
53 | item.setAttribute('allowevents', "true");
54 | item.style.backgroundColor = out ? '#AACCFF' : '#CCFFCC';
55 |
56 | var cell = document.createElement('listcell');
57 | cell.setAttribute('label', new Date().toLocaleTimeString()); // timestamp
58 | item.appendChild(cell);
59 |
60 | cell = document.createElement('listcell');
61 | cell.setAttribute('label', message.getType(true)+'-'+message.getCode(true)); // type
62 | item.appendChild(cell);
63 |
64 | cell = document.createElement('listcell');
65 | cell.setAttribute('label', message.getMID() + (message.isConfirmable() ? (' (' + message.getRetries() + ')') : ''));
66 | item.appendChild(cell);
67 |
68 | cell = document.createElement('listcell');
69 | cell.setAttribute('label', message.getToken());
70 | cell.tooltipText = message.getToken();
71 | item.appendChild(cell);
72 |
73 | cell = document.createElement('listcell');
74 | cell.setAttribute('label', message.getOptions(true));
75 | cell.tooltipText = message.getOptions(true);
76 | item.appendChild(cell);
77 |
78 | cell = document.createElement('listcell');
79 | cell.setAttribute('label', message.getPayloadText());
80 | cell.tooltipText = message.getPayloadText();
81 | item.appendChild(cell);
82 |
83 | rows.appendChild( item );
84 |
85 | rows.ensureElementIsVisible(item);
86 | };
87 |
88 | Copper.bytes2hexedit = function(bytes) {
89 |
90 | if (bytes==null) return '';
91 |
92 | let str ='';
93 | let show = '';
94 | for (let b in bytes) {
95 | str += Copper.Copper.leadingZero(bytes[b].toString(16));
96 | show += bytes[b]<32 ? '·' : String.fromCharCode(bytes[b]);
97 | if (b % 16 == 15) {
98 | str += " | ";
99 | str += show;
100 | str += '\n';
101 | show = '';
102 | } else {
103 | str += ' ';
104 | }
105 | }
106 | return str;
107 | }
108 |
109 | Copper.logEvent = function(text) {
110 | document.getElementById('log_event_log').value += text + '\n';
111 | };
112 |
113 | Copper.logWarning = function(text) {
114 | Copper.logEvent('WARNING: ' + text);
115 | window.setTimeout(
116 | function() { alert('WARNING: '+ text); },
117 | 0);
118 | };
119 |
120 | Copper.logError = function(error, skip) {
121 | var message = 'ERROR: ' + error.message;
122 | if (!skip && error.stack) {
123 | message += '\n\t' + error.stack.replace(/\n/, '\n\t');
124 | }
125 | Copper.logEvent(message);
126 | if (Copper.endpoint) {
127 | Copper.endpoint.cancelTransactions();
128 | }
129 | window.setTimeout(
130 | function(msg) { alert(msg); },
131 | 0, message);
132 | };
133 |
134 | Copper.debug = function(object) {
135 | let str = "";
136 | for (let x in object) str += x+": "+object[x]+"\n-----\n";
137 | alert(str);
138 | };
139 |
--------------------------------------------------------------------------------
/content/Main.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2016, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Main program code for the Copper CoAP Browser
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | // file IO
39 | Components.utils.import("resource://gre/modules/NetUtil.jsm");
40 |
41 | Copper.mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
42 | .getInterface(Components.interfaces.nsIWebNavigation)
43 | .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
44 | .rootTreeItem
45 | .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
46 | .getInterface(Components.interfaces.nsIDOMWindow);
47 |
48 | Copper.prefManager = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);
49 |
50 | Copper.hostname = '';
51 | Copper.port = -1;
52 | Copper.path = '/';
53 | Copper.query = '';
54 |
55 | Copper.endpoint = null;
56 | Copper.observer = null;
57 |
58 | Copper.resources = new Object();
59 | Copper.resourcesCached = true;
60 |
61 | Copper.uploadMethod = 0;
62 | Copper.uploadBlocks = null;
63 | Copper.uploadHandler = null;
64 |
65 | Copper.downloadMethod = 0;
66 | Copper.downloadHandler = null;
67 |
68 | Copper.behavior = {
69 | requests: 'con',
70 | retransmission: true,
71 | sendDuplicates: false,
72 | showUnknown: false,
73 | rejectUnknown: true,
74 | sendUriHost: false,
75 | sendSize1: false,
76 | blockSize: 0,
77 | observeToken: true,
78 | observeCancellation: 'lazy'
79 | };
80 |
81 | Copper.payload = {
82 | mode: 'text',
83 | file: '',
84 | loaded: false,
85 | data: null
86 | };
87 |
88 |
89 | // Life cycle functions
90 | ////////////////////////////////////////////////////////////////////////////////
91 |
92 | Copper.main = function() {
93 |
94 | Copper.logEvent('==============================================================================');
95 | Copper.logEvent('= INITIALIZING COPPER ========================================================');
96 | Copper.logEvent('==============================================================================');
97 |
98 | window.addEventListener('beforeunload', function(event) { Copper.beforeunload(event); });
99 | window.addEventListener('unload', function(event) { Copper.unload(event); });
100 |
101 | // get settings from preferences
102 | var onloadAction = null;
103 | try {
104 |
105 | document.getElementById('view_tree_split').setAttribute('state', Copper.prefManager.getBoolPref('extensions.copper.view-tree') ? 'open' : 'collapsed');
106 | document.getElementById('view_debug_split').setAttribute('state', Copper.prefManager.getBoolPref('extensions.copper.view-debug') ? 'open' : 'collapsed');
107 | document.getElementById('view_log_split').setAttribute('state', Copper.prefManager.getBoolPref('extensions.copper.view-log') ? 'open' : 'collapsed');
108 |
109 | onloadAction = Copper.prefManager.getCharPref('extensions.copper.onload-action');
110 |
111 | Copper.loadWindow();
112 | Copper.loadBehavior();
113 | Copper.loadDebugOptions();
114 | Copper.initDebugContentFormats();
115 |
116 | if (Copper.prefManager.getBoolPref('extensions.copper.plugtest.menu')) {
117 | document.getElementById('menu_plugtest').hidden = false;
118 | Copper.loadPlugtest();
119 | }
120 |
121 | if (Copper.prefManager.getBoolPref('extensions.copper.enable-etch')) {
122 | document.getElementById('toolbar_fetch').hidden = false;
123 | document.getElementById('toolbar_patch').hidden = false;
124 | document.getElementById('toolbar_ipatch').hidden = false;
125 | }
126 |
127 | } catch (ex) {
128 | Copper.logError(ex);
129 | }
130 |
131 | // open location
132 | try {
133 | Copper.parseUri(document.location.href);
134 |
135 | // set up datagram and transaction layer
136 | Copper.endpoint = new Copper.TransactionHandler(new Copper.UdpClient(Copper.hostname, Copper.port), Copper.behavior.retransmissions);
137 | Copper.endpoint.registerCallback(Copper.defaultHandler);
138 |
139 | // enable observing
140 | Copper.observer = new Copper.Observing();
141 |
142 | Copper.loadCachedResources();
143 | Copper.updateResourceLinks();
144 |
145 | Copper.loadPayload();
146 |
147 | // handle auto-request after redirect
148 | if (onloadAction!='') {
149 |
150 | Copper.logEvent('INFO: onloadAction defined ('+onloadAction+')');
151 |
152 | window.setTimeout(
153 | function(action) {
154 | switch (action) {
155 | case 'userObserve': Copper.userObserve(); break;
156 | default: Copper.userRequest(action); break;
157 | }
158 | },
159 | 0, onloadAction);
160 |
161 | // reset onloadAction
162 | Copper.prefManager.setCharPref('extensions.copper.onload-action', '');
163 | }
164 |
165 | Copper.updateLabel('info_code', "Opened " + decodeURI(document.location.href));
166 |
167 | } catch (ex) {
168 | Copper.errorHandler({getCopperCode:function(){return ex.message;}, getPayload:function(){return ex.stacktrace;}});
169 | Copper.logEvent('ERROR: ' + ex.message + '\n\t' + ex.stack.replace(/\n/, '\n\t'));
170 | }
171 | };
172 |
173 |
174 | Copper.beforeunload = function(event) {
175 |
176 | if (Copper.observer.subscription!=null) {
177 | Copper.logEvent('WARNING: Leaving resource while observing');
178 | Copper.updateLabel('info_code', "Copper: Still observing resource");
179 | event.preventDefault();
180 | }
181 | };
182 |
183 | Copper.unload = function(event) {
184 |
185 | if (Copper.observer.subscription!=null) {
186 | Copper.logEvent('INFO: Canceling Observe in unload handler');
187 | Copper.observer.unsubscribe(true);
188 | }
189 |
190 | // shut down socket required for refresh (F5), client might be null for parseUri() redirects
191 | if (Copper.endpoint!=null) {
192 | Copper.endpoint.shutdown();
193 | }
194 |
195 | Copper.saveBehavior();
196 | Copper.savePayload();
197 | Copper.saveDebugOptions();
198 | Copper.savePlugtest();
199 | Copper.saveWindow();
200 | };
201 |
202 |
203 | // Toolbar commands
204 | ////////////////////////////////////////////////////////////////////////////////
205 |
206 | Copper.userRequest = function(method) {
207 | Copper.endpoint.cancelTransactions();
208 | var uri = Copper.checkUri(null, method);
209 |
210 | Copper.sendRequest(method, uri);
211 | };
212 |
213 | Copper.userObserve = function() {
214 | var uri = Copper.checkUri(null, 'userObserve');
215 |
216 | Copper.observe(uri);
217 | };
218 |
219 | Copper.userDiscover = function() {
220 | Copper.logEvent('INFO: resetting cached resources');
221 | document.getElementById('toolbar_discover').image = 'chrome://copper/skin/spinner.gif';
222 | Copper.prefManager.setCharPref('extensions.copper.resources.'+Copper.hostname+':'+Copper.port, '' );
223 | Copper.resources = new Object();
224 |
225 | Copper.discover();
226 | };
227 |
228 |
229 | // Request commands
230 | ////////////////////////////////////////////////////////////////////////////////
231 |
232 | Copper.sendRequest = function(method, uri, callback) {
233 | if (!uri) throw new Error('No URI specified');
234 |
235 | Copper.downloadMethod = method;
236 |
237 | if (method == Copper.GET || method == Copper.DELETE) {
238 |
239 | if (Copper.behavior.blockSize!=0) {
240 | Copper.sendBlockwise2(uri, parseInt(document.getElementById('debug_option_block2').value), Copper.behavior.blockSize, callback);
241 | return;
242 | }
243 |
244 | try {
245 | var message = new Copper.CoapMessage(Copper.getRequestType(), method, uri);
246 |
247 | Copper.checkDebugOptions(message);
248 |
249 | Copper.clearLabels();
250 | Copper.endpoint.send( message, callback );
251 | } catch (ex) {
252 | Copper.logError(ex);
253 | }
254 |
255 | } else {
256 |
257 | var num = parseInt(document.getElementById('debug_option_block2').value);
258 |
259 | if (Copper.downloadMethod == method && num>0) {
260 | Copper.sendBlockwise2(uri, num, Copper.behavior.blockSize, callback);
261 | } else {
262 | Copper.doUpload(method, uri, callback);
263 | }
264 | }
265 | };
266 |
267 | Copper.sendBlockwise2 = function(uri, num, size, callback) {
268 | try {
269 | if (!uri) throw new Error('No URI specified');
270 | if (!num) num = 0;
271 | if (!size) size = Copper.behavior.blockSize;
272 |
273 | if (Copper.downloadMethod==0) {
274 | throw new Error('No download in progress');
275 | }
276 |
277 | if (callback) Copper.downloadHandler = callback;
278 |
279 | var message = new Copper.CoapMessage(Copper.getRequestType(), Copper.downloadMethod, uri);
280 |
281 | Copper.checkDebugOptions(message);
282 |
283 | // (re)set to useful block option
284 | message.setBlock2(num, size);
285 |
286 | Copper.clearLabels(num==0);
287 | Copper.endpoint.send( message, Copper.blockwiseHandler );
288 | } catch (ex) {
289 | Copper.logError(ex);
290 | }
291 | };
292 |
293 | Copper.doUpload = function(method, uri, callback) {
294 | try {
295 | if (uri===undefined) throw new Error('No URI specified');
296 |
297 | // load payload
298 | let pl = '';
299 | if (Copper.payload.mode=='text') {
300 | pl = Copper.str2bytes(document.getElementById('payload_text').value);
301 | } else if (Copper.payload.file!='') {
302 | if (!Copper.payload.loaded) {
303 | // file loading as async, wait until done
304 | window.setTimeout(function() {Copper.doUpload(method, uri, callback);}, 50);
305 | return;
306 | }
307 | pl = Copper.data2bytes(Copper.payload.data);
308 | } else {
309 | Copper.logWarning('No payload data defined');
310 | return;
311 | }
312 |
313 | // store payload in case server requests blockwise upload
314 | Copper.uploadMethod = method; // POST or PUT
315 | Copper.uploadBlocks = pl;
316 | Copper.downloadMethod = method; // in case of Block2 response
317 |
318 | // blockwise uploads
319 | if (Copper.behavior.blockSize!=0 && pl.length > Copper.behavior.blockSize) {
320 | Copper.sendBlockwise1(uri, parseInt(document.getElementById('debug_option_block1').value), Copper.behavior.blockSize, callback);
321 | return;
322 | }
323 |
324 | var message = new Copper.CoapMessage(Copper.getRequestType(), method, uri, pl);
325 |
326 | Copper.checkDebugOptions(message);
327 |
328 | if (Copper.behavior.sendSize1) {
329 | Copper.logEvent('INFO: Send auto Size1 option');
330 | message.setSize1(pl.length);
331 | document.getElementById('debug_option_size1').value = pl.length;
332 | }
333 |
334 | Copper.clearLabels();
335 | Copper.endpoint.send( message, callback );
336 | } catch (ex) {
337 | Copper.logError(ex);
338 | }
339 | }
340 |
341 | Copper.sendBlockwise1 = function(uri, num, size, callback) {
342 | try {
343 | if (uri===undefined) throw new Error('No URI specified');
344 | if (!num) num = 0;
345 | if (size===undefined) size = Copper.behavior.blockSize;
346 |
347 | if (Copper.uploadBlocks==null || Copper.uploadMethod==0) {
348 | throw new Error('No upload in progress, cancelling');
349 | }
350 | if ( (num>0) && (size*(num-1) > Copper.uploadBlocks.length)) { // num-1, as we are called with the num to send, not was has been send
351 | throw new Error('Debug Block1 out of payload scope');
352 | }
353 |
354 | let more = false;
355 | let pl = Copper.uploadBlocks.slice(size*num, size*(num+1));
356 |
357 | // more blocks?
358 | if (Copper.uploadBlocks.length > (num+1) * size) { // num+1, as we start counting at 0...
359 | more = true;
360 | }
361 |
362 | if (callback) Copper.uploadHandler = callback;
363 |
364 | var message = new Copper.CoapMessage(Copper.getRequestType(), Copper.uploadMethod, uri, pl);
365 |
366 | Copper.checkDebugOptions(message);
367 |
368 | if (Copper.behavior.sendSize1) {
369 | Copper.logEvent('INFO: Send auto Size1 option');
370 | message.setSize1(Copper.uploadBlocks.length);
371 | document.getElementById('debug_option_size1').value = Copper.uploadBlocks.length;
372 | }
373 |
374 | message.setBlock1(num, size, more);
375 |
376 | Copper.clearLabels(num==0);
377 | Copper.endpoint.send( message, Copper.blockwiseHandler );
378 | } catch (ex) {
379 | Copper.logError(ex);
380 | }
381 | };
382 |
383 | Copper.observe = function(uri) {
384 | try {
385 | Copper.observer.subscribe(uri, Copper.observingHandler);
386 |
387 | } catch (ex) {
388 | Copper.logError(ex);
389 | }
390 | };
391 |
392 | Copper.discover = function(num, size) {
393 | try {
394 | let message = new Copper.CoapMessage(Copper.getRequestType(), Copper.GET, Copper.WELL_KNOWN_RESOURCES);
395 |
396 | if (num!==undefined) {
397 | Copper.logEvent('INFO: Continuing discovery with Block '+num+' size '+size);
398 | if (size===undefined) size = Copper.behavior.blockSize;
399 | message.setBlock2(num, size);
400 | }
401 |
402 | Copper.endpoint.send( message, Copper.discoverHandler );
403 | } catch (ex) {
404 | Copper.logError(ex);
405 | }
406 | };
407 |
408 | // Sends a CoAP ping which is an empty CON message
409 | Copper.ping = function() {
410 | try {
411 | Copper.endpoint.cancelTransactions();
412 |
413 | var message = new Copper.CoapMessage(Copper.MSG_TYPE_CON);
414 |
415 | Copper.clearLabels();
416 | Copper.endpoint.send( message, Copper.pingHandler );
417 | } catch (ex) {
418 | Copper.logError(ex);
419 | }
420 | };
--------------------------------------------------------------------------------
/content/Observing.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Code handling Observing Resources
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | Copper.ObserveEntry = function(uri, cb, token) {
39 | this.uri = uri;
40 | this.callback = cb;
41 | if (token!=null) {
42 | this.token = token;
43 | }
44 |
45 | return this;
46 | };
47 | Copper.ObserveEntry.prototype = {
48 | uri : null,
49 | callback: null,
50 | token : null,
51 | lastMID: -1
52 | };
53 |
54 | Copper.Observing = function() {
55 | // maybe support multiple subscriptions via sidebar in the future
56 | //this.subscriptions = new Object();
57 |
58 | return this;
59 | };
60 |
61 | Copper.Observing.prototype = {
62 |
63 | pending : null,
64 | subscription : null,
65 |
66 | subscribe : function(uri, cb) {
67 | // check for existing subscriptions
68 | if (this.subscription) {
69 | this.unsubscribe();
70 | return;
71 | }
72 |
73 | Copper.logEvent('INFO: Subscribing to ' + uri);
74 |
75 | var subscribe = new Copper.CoapMessage(Copper.getRequestType(), Copper.GET, uri);
76 |
77 | // add all debug options
78 | Copper.checkDebugOptions(subscribe);
79 |
80 | // set token depending on the behavior config
81 | if (Copper.behavior.observeToken && subscribe.getToken()) {
82 | subscribe.setToken( new Array(parseInt(Math.random()*0x100), parseInt(Math.random()*0x100)) );
83 | // update debug options
84 | if (document.getElementById('chk_debug_options').checked) {
85 | document.getElementById('debug_option_token').value = subscribe.getToken();
86 | }
87 | }
88 |
89 | if (Copper.behavior.blockSize!=0) {
90 | subscribe.setBlock2(0, Copper.behavior.blockSize);
91 | }
92 |
93 | this.pending = new Copper.ObserveEntry(uri, cb, subscribe.getToken());
94 |
95 | var that = this;
96 | Copper.endpoint.registerToken(subscribe.getToken(), Copper.myBind(that, that.handle));
97 |
98 | try {
99 |
100 | subscribe.setObserve(0);
101 |
102 | var that = this;
103 | Copper.clearLabels();
104 | Copper.endpoint.send(subscribe, Copper.myBind(that, that.handle));
105 | } catch (ex) {
106 | Copper.logError(ex);
107 | }
108 | },
109 |
110 | unsubscribe : function(proactive) {
111 | if (this.subscription) {
112 |
113 | try {
114 | if (Copper.behavior.observeCancellation=='get' || proactive===true) {
115 |
116 | Copper.logEvent('INFO: Unsubscribing ' + this.subscription.uri + ' via proactive cancellation');
117 |
118 | Copper.downloadMethod = Copper.GET;
119 |
120 | let uri = Copper.checkUri(); // get current URI
121 | var cancel = new Copper.CoapMessage(Copper.MSG_TYPE_CON, Copper.GET, uri); // always use CON
122 |
123 | // add all debug options also for cancel
124 | Copper.checkDebugOptions(cancel);
125 | if (Copper.behavior.blockSize!=0) {
126 | cancel.setBlock2(0, Copper.behavior.blockSize);
127 | }
128 |
129 | cancel.setToken(this.subscription.token);
130 | cancel.setObserve(1);
131 |
132 | Copper.clearLabels();
133 | var that = this;
134 | Copper.endpoint.send( cancel, Copper.myBind(that, that.handle));
135 |
136 | } else {
137 |
138 | Copper.logEvent('INFO: Unsubscribing ' + this.subscription.uri + ' via reactive cancellation');
139 |
140 | // forget token for garbage collection
141 | Copper.endpoint.deRegisterToken(this.subscription.token);
142 |
143 | if (Copper.behavior.observeCancellation=='rst' && this.subscription.lastMID!=-1) {
144 | // Send a RST now
145 | var rst = new Copper.CoapMessage(Copper.MSG_TYPE_RST);
146 | rst.setMID(this.subscription.lastMID);
147 | Copper.endpoint.send( rst );
148 | }
149 |
150 | this.clean();
151 | }
152 |
153 | } catch (ex) {
154 | Copper.logError(ex);
155 | }
156 |
157 | Copper.updateLabel('info_code', 'Copper: Canceling Observe', false); // call after displayMessageInfo()
158 | }
159 | },
160 |
161 | handle : function(message) {
162 |
163 | Copper.logEvent('OBSERVE: handle()');
164 |
165 | if (message.getCode()==Copper.EMPTY) return;
166 |
167 | if (this.pending) {
168 |
169 | // check if server supports observing this resource
170 | if (message.isOption(Copper.OPTION_OBSERVE)) {
171 |
172 | this.subscription = new Copper.ObserveEntry(this.pending.uri, this.pending.callback, message.getToken());
173 | delete this.pending;
174 |
175 | document.getElementById('toolbar_observe').image = 'chrome://copper/skin/tool_unobserve.png';
176 | document.getElementById('toolbar_observe').label = 'Cancel ';
177 |
178 | this.subscription.lastMID = (message.getType()==Copper.MSG_TYPE_NON) ? message.getMID() : -1;
179 |
180 | this.subscription.callback(message);
181 |
182 | } else {
183 | Copper.endpoint.deRegisterToken(this.pending.token);
184 | delete this.pending;
185 |
186 | message.getCopperCode = function() { return 'Resource not observable'; };
187 |
188 | Copper.defaultHandler(message);
189 | }
190 |
191 | } else if (this.subscription) {
192 | this.subscription.lastMID = (message.getType()==Copper.MSG_TYPE_NON) ? message.getMID() : -1;
193 |
194 | let callback = this.subscription.callback;
195 |
196 | if (message.getObserve()==null || !message.isSuccess()) {
197 | Copper.endpoint.deRegisterToken(message.getToken());
198 | this.clean();
199 | }
200 |
201 | callback(message);
202 |
203 | } else {
204 | Copper.logError(new Error('Illegal Observe state'));
205 | }
206 | },
207 |
208 | clean : function() {
209 | delete this.subscription;
210 |
211 | document.getElementById('toolbar_observe').image = 'chrome://copper/skin/tool_observe.png';
212 | document.getElementById('toolbar_observe').label = 'Observe';
213 | }
214 | };
215 |
--------------------------------------------------------------------------------
/content/Options.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Code for the options window.
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | Copper.Options = {
39 |
40 | clearResourceCache : function() {
41 | var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.copper.resources");
42 |
43 | try {
44 | if (confirm('This will delete '+prefs.getChildList('', {}).length+' entries. Continue?')) {
45 | prefs.deleteBranch('');
46 | }
47 | } catch (ex) {
48 | alert(ex);
49 | }
50 | },
51 |
52 | clearPayloadCache : function() {
53 | var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.copper.payloads");
54 |
55 | try {
56 | if (confirm('This will delete '+prefs.getChildList('', {}).length+' entries. Continue?')) {
57 | prefs.deleteBranch('');
58 | }
59 | } catch (ex) {
60 | alert(ex);
61 | }
62 | }
63 | };
64 |
65 |
--------------------------------------------------------------------------------
/content/Renderers.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2016, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Content-type rendering functions
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | // Rendering functions
39 | ////////////////////////////////////////////////////////////////////////////////
40 |
41 | Copper.renderText = function(message) {
42 | Copper.updateLabel('packet_payload', Copper.bytes2str(message.getPayload()), false);
43 | let str = Copper.bytes2str(message.getPayload());
44 | if (str.match(/^#[0-9a-f]{3,6}$/i) || str.match(/´rgb\(\s*[0-9]+\s*,\s*[0-9]+\s*,\s*[0-9]+\s*\)$/i)) {
45 |
46 | // view corresponding render element
47 | document.getElementById('rendered_img').style.display = 'none';
48 | document.getElementById('rendered_div').style.display = 'block';
49 |
50 | document.getElementById('tab_rendered').style.backgroundColor = str.toLowerCase();
51 | document.getElementById('tabs_payload').selectedIndex = 1;
52 | } else {
53 | document.getElementById('tab_rendered').style.backgroundColor = '';
54 | document.getElementById('tabs_payload').selectedIndex = 0;
55 | }
56 | };
57 |
58 | Copper.renderImage = function(message) {
59 |
60 | if (!message.getBlock2More()) {
61 | // only render binary when transfer is complete (binary is heavy)
62 | Copper.renderBinary(message);
63 | }
64 |
65 | // view corresponding render element
66 | document.getElementById('rendered_div').style.display = 'none';
67 | document.getElementById('rendered_img').style.display = 'block';
68 |
69 | // causes flickering, but partially added data does not draw anyway
70 | document.getElementById('rendered_img').src = 'data:'+Copper.getContentFormatName(message.getContentFormat())+';base64,'+btoa( Copper.bytes2data(message.getPayload()) );
71 | document.getElementById('tab_rendered').style.backgroundColor = '';
72 | document.getElementById('tabs_payload').selectedIndex = 1;
73 | };
74 |
75 | Copper.renderBinary = function(message) {
76 |
77 | var pl = message.getPayload();
78 |
79 | // Clear content first
80 | Copper.updateLabel('packet_payload', '', false);
81 | var line = '';
82 | for (var i in pl) {
83 | line += Copper.leadingZero(pl[i].toString(16).toUpperCase());
84 |
85 | if (i % 16 == 15) {
86 | line += ' | ';
87 | for (var j=i-15; j<=i; ++j) {
88 | if (pl[j] < 32 || pl[j] >= 127) {
89 | line += '·';
90 | } else {
91 | line += String.fromCharCode(pl[j] & 0xFF);
92 | }
93 | }
94 | line += '\n';
95 | Copper.updateLabel('packet_payload', line, true);
96 | line = '';
97 | } else if (i % 2 == 1) {
98 | line += ' ';
99 | }
100 | }
101 |
102 | // incomplete lines
103 | if ((parseInt(i)+1) % 16 != 0) {
104 | // complete line with spaces
105 | for (var j=0; j<39-((parseInt(i)+1)%16)*2 - ((parseInt(i)+1)%16)/2; ++j) {
106 | line += ' ';
107 | }
108 |
109 | line += ' | ';
110 | for (var j=i-(i%16); j<=i; ++j) {
111 | if (pl[j] < 32) {
112 | line += '·';
113 | } else {
114 | line += String.fromCharCode(pl[j] & 0xFF);
115 | }
116 | }
117 | Copper.updateLabel('packet_payload', line, true);
118 | }
119 |
120 | document.getElementById('tabs_payload').selectedIndex = 0;
121 | };
122 |
123 |
124 | Copper.renderLinkFormat = function(message) {
125 |
126 | // Print raw Link Format in case parsing fails
127 | Copper.renderText(message);
128 |
129 | // The box for output at the top-level
130 | document.getElementById('rendered_img').style.display = 'none';
131 | var view = document.getElementById('rendered_div');
132 | view.style.display = 'block';
133 |
134 | while (view.hasChildNodes()) {
135 | view.removeChild(view.firstChild);
136 | }
137 | view.setAttribute("class", "link-content");
138 |
139 | var parsedObj = Copper.parseLinkFormat( Copper.bytes2str(message.getPayload()) );
140 |
141 | view.appendChild( Copper.renderLinkFormatUtils.getXulLinks(parsedObj) );
142 |
143 | document.getElementById('tab_rendered').style.backgroundColor = '';
144 | document.getElementById('tabs_payload').selectedIndex = 1;
145 | };
146 |
147 | Copper.renderLinkFormatUtils = {
148 |
149 | htmlns: "http://www.w3.org/1999/xhtml",
150 |
151 | getXulLinks: function(value) {
152 | if (typeof value != 'object') {
153 | return null;
154 | }
155 |
156 | var xulObj = document.createElementNS(this.htmlns, "ul");
157 | for (var uri in value) {
158 | this.addXulLink(xulObj, value[uri], uri);
159 | }
160 |
161 | return xulObj;
162 | },
163 |
164 | addXulLink: function(xulObj, attribs, key) {
165 |
166 | var xulChild = document.createElementNS(this.htmlns, "li");
167 |
168 | var label = document.createElement("label");
169 | label.setAttribute("class", "uri");
170 | label.setAttribute("value", key);
171 | xulChild.appendChild(label);
172 | xulChild.appendChild( this.getXulObject(attribs) );
173 |
174 | xulObj.appendChild(xulChild);
175 | },
176 |
177 | getXulObject: function(value) {
178 |
179 | if (typeof value != 'object') {
180 | return null;
181 | }
182 |
183 | var xulObj = document.createElementNS(this.htmlns, "ul");
184 |
185 | if (Array.isArray(value)) {
186 | xulObj.setAttribute("class", "array");
187 | for (var i = 0; i < value.length; i ++) {
188 | this.addXulChild(xulObj, value[i]);
189 | }
190 | } else {
191 | // object
192 | xulObj.setAttribute("class", "object");
193 | for (var prop in value) {
194 | this.addXulChild(xulObj, value[prop], prop);
195 | }
196 | }
197 |
198 | return xulObj;
199 | },
200 |
201 | addXulChild: function(xulObj, value, key) {
202 |
203 | var xulChild = document.createElementNS(this.htmlns, "li");
204 |
205 | // If the value has a label (object properties will have labels)
206 | if (key != null) {
207 | var label = document.createElement("label");
208 | label.setAttribute("class", "label");
209 | label.setAttribute("value", key + ":");
210 | xulChild.appendChild(label);
211 | }
212 |
213 | if (typeof value == 'object' && value != null) {
214 | xulChild.appendChild( this.getXulObject(value) );
215 | } else {
216 | xulChild.appendChild( this.getXulValue(value) );
217 | }
218 |
219 | xulObj.appendChild(xulChild);
220 | },
221 |
222 | getXulValue: function(value) {
223 | var xulObj = document.createElement("description");
224 | switch (typeof value) {
225 | case 'object':
226 | if (!value) {
227 | xulObj.setAttribute("value", 'null');
228 | xulObj.setAttribute("class", "null");
229 | return xulObj;
230 | }
231 | return null;
232 |
233 | case 'string':
234 | xulObj.appendChild( document.createTextNode(String(value)) );
235 | xulObj.setAttribute("class", "string");
236 | return xulObj;
237 |
238 | case 'number':
239 | xulObj.setAttribute("value", isFinite(value) ? String(value) : 'null');
240 | if (Math.floor(value) == value) {
241 | xulObj.setAttribute("class", "int");
242 | } else {
243 | xulObj.setAttribute("class", "float");
244 | }
245 | return xulObj;
246 |
247 | case 'boolean':
248 | xulObj.setAttribute("value", String(value));
249 | xulObj.setAttribute("class", "bool");
250 | return xulObj;
251 |
252 | case 'null':
253 | xulObj.setAttribute("value", String(value));
254 | xulObj.setAttribute("class", "null");
255 | return xulObj;
256 |
257 | default:
258 | return null;
259 | }
260 | }
261 | };
262 |
263 | Copper.renderCBOR = function(message) {
264 | // The box for output at the top-level
265 | document.getElementById('rendered_img').style.display = 'none';
266 |
267 | var view = document.getElementById('rendered_div');
268 | view.style.display = 'block';
269 |
270 | while (view.hasChildNodes()) {
271 | view.removeChild(view.firstChild);
272 | }
273 |
274 | view.setAttribute("class", "json-content");
275 | var parsedObj = Copper.parseCBOR(message.getPayload());
276 |
277 | // Turn the Javascript object into XUL objects
278 | if (typeof parsedObj == 'object') {
279 | view.appendChild( Copper.renderJSONutils.getXulObject(parsedObj) );
280 | document.getElementById('tab_rendered').style.backgroundColor = '';
281 | document.getElementById('tabs_payload').selectedIndex = 1;
282 | } else {
283 | Copper.logError(new Error('Top level element is not an object'));
284 | }
285 | };
286 |
287 | Copper.renderJSON = function(message) {
288 |
289 | // Print raw JSON in case parsing fails
290 | Copper.renderText(message);
291 |
292 | // The box for output at the top-level
293 | document.getElementById('rendered_img').style.display = 'none';
294 | var view = document.getElementById('rendered_div');
295 | view.style.display = 'block';
296 |
297 | while (view.hasChildNodes()) {
298 | view.removeChild(view.firstChild);
299 | }
300 | view.setAttribute("class", "json-content");
301 |
302 | var pl = Copper.bytes2str(message.getPayload()).replace(/'/g, '"');
303 |
304 | try {
305 | // Parse the JSON
306 | var parsedObj = JSON.parse(pl);
307 | // Turn the Javascript object into XUL objects
308 | if (typeof parsedObj == 'object') {
309 | view.appendChild( Copper.renderJSONutils.getXulObject(parsedObj) );
310 | document.getElementById('tab_rendered').style.backgroundColor = '';
311 | document.getElementById('tabs_payload').selectedIndex = 1;
312 | } else {
313 | Copper.logError(new Error('Top level element is not a JSON object'));
314 | }
315 | } catch (ex) {
316 | Copper.logError(ex);
317 | }
318 |
319 | };
320 |
321 | Copper.renderJSONutils = {
322 |
323 | htmlns: "http://www.w3.org/1999/xhtml",
324 |
325 | getXulObject: function(value) {
326 | if (typeof value != 'object') {
327 | return null;
328 | }
329 |
330 | var xulObj = document.createElementNS(this.htmlns, "ul");
331 |
332 | if (Array.isArray(value)) {
333 | xulObj.setAttribute("class", "array");
334 |
335 | if (value.length>0) {
336 | var label = document.createElement("label");
337 | label.setAttribute("value", "(length " + value.length + ")");
338 | label.setAttribute("style", "color: gray;");
339 | xulObj.appendChild(label);
340 |
341 | for (var i = 0; i < value.length; i ++) {
342 | this.addXulChild(xulObj, value[i]);
343 | }
344 | } else {
345 | var label = document.createElement("label");
346 | label.setAttribute("value", " ");
347 | xulObj.appendChild(label);
348 | }
349 |
350 | } else {
351 | // object
352 | xulObj.setAttribute("class", "object");
353 | for (var prop in value) {
354 | this.addXulChild(xulObj, value[prop], prop);
355 | }
356 | }
357 |
358 | return xulObj;
359 | },
360 |
361 | addXulChild: function(xulObj, value, key) {
362 |
363 | var xulChild = document.createElementNS(this.htmlns, "li");
364 |
365 | // If the value has a label (object properties will have labels)
366 | if (key != null) {
367 | var label = document.createElement("label");
368 | label.setAttribute("class", "label");
369 | label.setAttribute("value", key + ":");
370 | xulChild.appendChild(label);
371 | }
372 |
373 | if(value instanceof Uint8Array) {
374 | value = JSON.stringify(value);
375 | }
376 |
377 | if (typeof value == 'object' && value != null) {
378 | xulChild.appendChild( this.getXulObject(value) );
379 | } else {
380 | xulChild.appendChild( this.getXulValue(value) );
381 | }
382 |
383 | xulObj.appendChild(xulChild);
384 | },
385 |
386 | getXulValue: function(value) {
387 | var xulObj = document.createElement("description");
388 | switch (typeof value) {
389 | case 'object':
390 | if (!value) {
391 | xulObj.setAttribute("value", 'null');
392 | xulObj.setAttribute("class", "null");
393 | return xulObj;
394 | }
395 | return null;
396 |
397 | case 'string':
398 | xulObj.appendChild( document.createTextNode(String(value)) );
399 | xulObj.setAttribute("class", "string");
400 | return xulObj;
401 |
402 | case 'number':
403 | xulObj.setAttribute("value", isFinite(value) ? String(value) : 'null');
404 | if (Math.floor(value) == value) {
405 | xulObj.setAttribute("class", "int");
406 | } else {
407 | xulObj.setAttribute("class", "float");
408 | }
409 | return xulObj;
410 |
411 | case 'boolean':
412 | xulObj.setAttribute("value", String(value));
413 | xulObj.setAttribute("class", "bool");
414 | return xulObj;
415 |
416 | case 'null':
417 | xulObj.setAttribute("value", String(value));
418 | xulObj.setAttribute("class", "null");
419 | return xulObj;
420 |
421 | default:
422 | return null;
423 | }
424 | }
425 | };
426 |
427 | Copper.renderEXI = function(message) {
428 | Copper.updateLabel('packet_payload', Copper.bytes2data(message.getPayload()), message.getBlock2Number()>0);
429 | document.getElementById('tabs_payload').selectedIndex = 0;
430 | };
431 |
--------------------------------------------------------------------------------
/content/ResourceViews.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Views for resources
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 |
39 | // Tree view
40 | ////////////////////////////////////////////////////////////////////////////////
41 |
42 | Copper.clearTree = function() {
43 | var elems = document.getElementById('resource_elems');
44 | while (elems.hasChildNodes()) {
45 | elems.removeChild(elems.firstChild);
46 | }
47 | };
48 |
49 | Copper.addTreeResource = function(uri, attributes) {
50 |
51 | var tree = document.getElementById('resource_tree');
52 | var segments;
53 |
54 | var uriTokens = uri.match(/([a-zA-Z]+:\/\/)([^\/]+)(.*)/);
55 |
56 | if (uriTokens) {
57 | // absolute URI
58 |
59 | if (uriTokens[1]=='coap://') {
60 | segments = uriTokens[3].split('/');
61 | segments.shift();
62 | segments.unshift(uriTokens[2]);
63 | } else {
64 | Copper.logEvent("WARNING: Non-CoAP resource "+uri+"'");
65 | return;
66 | }
67 | } else {
68 | segments = uri.split('/');
69 | segments.shift();
70 | segments.unshift(Copper.hostname + ':' + Copper.port);
71 | }
72 |
73 | var node = tree;
74 | //Copper.logEvent('Children: '+node.getElementsByTagName('treechildren')[0].childNodes.length);
75 |
76 | for (var i=0; i
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | (function(global, undefined) { "use strict";
26 | var POW_2_24 = Math.pow(2, -24),
27 | POW_2_32 = Math.pow(2, 32),
28 | POW_2_53 = Math.pow(2, 53);
29 |
30 | function encode(value) {
31 | var data = new ArrayBuffer(256);
32 | var dataView = new DataView(data);
33 | var lastLength;
34 | var offset = 0;
35 |
36 | function ensureSpace(length) {
37 | var newByteLength = data.byteLength;
38 | var requiredLength = offset + length;
39 | while (newByteLength < requiredLength)
40 | newByteLength *= 2;
41 | if (newByteLength !== data.byteLength) {
42 | var oldDataView = dataView;
43 | data = new ArrayBuffer(newByteLength);
44 | dataView = new DataView(data);
45 | var uint32count = (offset + 3) >> 2;
46 | for (var i = 0; i < uint32count; ++i)
47 | dataView.setUint32(i * 4, oldDataView.getUint32(i * 4));
48 | }
49 |
50 | lastLength = length;
51 | return dataView;
52 | }
53 | function write() {
54 | offset += lastLength;
55 | }
56 | function writeFloat64(value) {
57 | write(ensureSpace(8).setFloat64(offset, value));
58 | }
59 | function writeUint8(value) {
60 | write(ensureSpace(1).setUint8(offset, value));
61 | }
62 | function writeUint8Array(value) {
63 | var dataView = ensureSpace(value.length);
64 | for (var i = 0; i < value.length; ++i)
65 | dataView.setUint8(offset + i, value[i]);
66 | write();
67 | }
68 | function writeUint16(value) {
69 | write(ensureSpace(2).setUint16(offset, value));
70 | }
71 | function writeUint32(value) {
72 | write(ensureSpace(4).setUint32(offset, value));
73 | }
74 | function writeUint64(value) {
75 | var low = value % POW_2_32;
76 | var high = (value - low) / POW_2_32;
77 | var dataView = ensureSpace(8);
78 | dataView.setUint32(offset, high);
79 | dataView.setUint32(offset + 4, low);
80 | write();
81 | }
82 | function writeTypeAndLength(type, length) {
83 | if (length < 24) {
84 | writeUint8(type << 5 | length);
85 | } else if (length < 0x100) {
86 | writeUint8(type << 5 | 24);
87 | writeUint8(length);
88 | } else if (length < 0x10000) {
89 | writeUint8(type << 5 | 25);
90 | writeUint16(length);
91 | } else if (length < 0x100000000) {
92 | writeUint8(type << 5 | 26);
93 | writeUint32(length);
94 | } else {
95 | writeUint8(type << 5 | 27);
96 | writeUint64(length);
97 | }
98 | }
99 |
100 | function encodeItem(value) {
101 | var i;
102 |
103 | if (value === false)
104 | return writeUint8(0xf4);
105 | if (value === true)
106 | return writeUint8(0xf5);
107 | if (value === null)
108 | return writeUint8(0xf6);
109 | if (value === undefined)
110 | return writeUint8(0xf7);
111 |
112 | switch (typeof value) {
113 | case "number":
114 | if (Math.floor(value) === value) {
115 | if (0 <= value && value <= POW_2_53)
116 | return writeTypeAndLength(0, value);
117 | if (-POW_2_53 <= value && value < 0)
118 | return writeTypeAndLength(1, -(value + 1));
119 | }
120 | writeUint8(0xfb);
121 | return writeFloat64(value);
122 |
123 | case "string":
124 | var utf8data = [];
125 | for (i = 0; i < value.length; ++i) {
126 | var charCode = value.charCodeAt(i);
127 | if (charCode < 0x80) {
128 | utf8data.push(charCode);
129 | } else if (charCode < 0x800) {
130 | utf8data.push(0xc0 | charCode >> 6);
131 | utf8data.push(0x80 | charCode & 0x3f);
132 | } else if (charCode < 0xd800) {
133 | utf8data.push(0xe0 | charCode >> 12);
134 | utf8data.push(0x80 | (charCode >> 6) & 0x3f);
135 | utf8data.push(0x80 | charCode & 0x3f);
136 | } else {
137 | charCode = (charCode & 0x3ff) << 10;
138 | charCode |= value.charCodeAt(++i) & 0x3ff;
139 | charCode += 0x10000;
140 |
141 | utf8data.push(0xf0 | charCode >> 18);
142 | utf8data.push(0x80 | (charCode >> 12) & 0x3f);
143 | utf8data.push(0x80 | (charCode >> 6) & 0x3f);
144 | utf8data.push(0x80 | charCode & 0x3f);
145 | }
146 | }
147 |
148 | writeTypeAndLength(3, utf8data.length);
149 | return writeUint8Array(utf8data);
150 |
151 | default:
152 | var length;
153 | if (Array.isArray(value)) {
154 | length = value.length;
155 | writeTypeAndLength(4, length);
156 | for (i = 0; i < length; ++i)
157 | encodeItem(value[i]);
158 | } else if (value instanceof Uint8Array) {
159 | writeTypeAndLength(2, value.length);
160 | writeUint8Array(value);
161 | } else {
162 | var keys = Object.keys(value);
163 | length = keys.length;
164 | writeTypeAndLength(5, length);
165 | for (i = 0; i < length; ++i) {
166 | var key = keys[i];
167 | encodeItem(key);
168 | encodeItem(value[key]);
169 | }
170 | }
171 | }
172 | }
173 |
174 | encodeItem(value);
175 |
176 | if ("slice" in data)
177 | return data.slice(0, offset);
178 |
179 | var ret = new ArrayBuffer(offset);
180 | var retView = new DataView(ret);
181 | for (var i = 0; i < offset; ++i)
182 | retView.setUint8(i, dataView.getUint8(i));
183 | return ret;
184 | }
185 |
186 | function decode(data, tagger, simpleValue) {
187 | var dataView = new DataView(data);
188 | var offset = 0;
189 |
190 | if (typeof tagger !== "function")
191 | tagger = function(value) { return value; };
192 | if (typeof simpleValue !== "function")
193 | simpleValue = function() { return undefined; };
194 |
195 | function read(value, length) {
196 | offset += length;
197 | return value;
198 | }
199 | function readArrayBuffer(length) {
200 | return read(new Uint8Array(data, offset, length), length);
201 | }
202 | function readFloat16() {
203 | var tempArrayBuffer = new ArrayBuffer(4);
204 | var tempDataView = new DataView(tempArrayBuffer);
205 | var value = readUint16();
206 |
207 | var sign = value & 0x8000;
208 | var exponent = value & 0x7c00;
209 | var fraction = value & 0x03ff;
210 |
211 | if (exponent === 0x7c00)
212 | exponent = 0xff << 10;
213 | else if (exponent !== 0)
214 | exponent += (127 - 15) << 10;
215 | else if (fraction !== 0)
216 | return fraction * POW_2_24;
217 |
218 | tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13);
219 | return tempDataView.getFloat32(0);
220 | }
221 | function readFloat32() {
222 | return read(dataView.getFloat32(offset), 4);
223 | }
224 | function readFloat64() {
225 | return read(dataView.getFloat64(offset), 8);
226 | }
227 | function readUint8() {
228 | return read(dataView.getUint8(offset), 1);
229 | }
230 | function readUint16() {
231 | return read(dataView.getUint16(offset), 2);
232 | }
233 | function readUint32() {
234 | return read(dataView.getUint32(offset), 4);
235 | }
236 | function readUint64() {
237 | return readUint32() * POW_2_32 + readUint32();
238 | }
239 | function readBreak() {
240 | if (dataView.getUint8(offset) !== 0xff)
241 | return false;
242 | offset += 1;
243 | return true;
244 | }
245 | function readLength(additionalInformation) {
246 | if (additionalInformation < 24)
247 | return additionalInformation;
248 | if (additionalInformation === 24)
249 | return readUint8();
250 | if (additionalInformation === 25)
251 | return readUint16();
252 | if (additionalInformation === 26)
253 | return readUint32();
254 | if (additionalInformation === 27)
255 | return readUint64();
256 | if (additionalInformation === 31)
257 | return -1;
258 | throw "Invalid length encoding";
259 | }
260 | function readIndefiniteStringLength(majorType) {
261 | var initialByte = readUint8();
262 | if (initialByte === 0xff)
263 | return -1;
264 | var length = readLength(initialByte & 0x1f);
265 | if (length < 0 || (initialByte >> 5) !== majorType)
266 | throw "Invalid indefinite length element";
267 | return length;
268 | }
269 |
270 | function appendUtf16data(utf16data, length) {
271 | for (var i = 0; i < length; ++i) {
272 | var value = readUint8();
273 | if (value & 0x80) {
274 | if (value < 0xe0) {
275 | value = (value & 0x1f) << 6
276 | | (readUint8() & 0x3f);
277 | length -= 1;
278 | } else if (value < 0xf0) {
279 | value = (value & 0x0f) << 12
280 | | (readUint8() & 0x3f) << 6
281 | | (readUint8() & 0x3f);
282 | length -= 2;
283 | } else {
284 | value = (value & 0x0f) << 18
285 | | (readUint8() & 0x3f) << 12
286 | | (readUint8() & 0x3f) << 6
287 | | (readUint8() & 0x3f);
288 | length -= 3;
289 | }
290 | }
291 |
292 | if (value < 0x10000) {
293 | utf16data.push(value);
294 | } else {
295 | value -= 0x10000;
296 | utf16data.push(0xd800 | (value >> 10));
297 | utf16data.push(0xdc00 | (value & 0x3ff));
298 | }
299 | }
300 | }
301 |
302 | function decodeItem() {
303 | var initialByte = readUint8();
304 | var majorType = initialByte >> 5;
305 | var additionalInformation = initialByte & 0x1f;
306 | var i;
307 | var length;
308 |
309 | if (majorType === 7) {
310 | switch (additionalInformation) {
311 | case 25:
312 | return readFloat16();
313 | case 26:
314 | return readFloat32();
315 | case 27:
316 | return readFloat64();
317 | }
318 | }
319 |
320 | length = readLength(additionalInformation);
321 | if (length < 0 && (majorType < 2 || 6 < majorType))
322 | throw "Invalid length";
323 |
324 | switch (majorType) {
325 | case 0:
326 | return length;
327 | case 1:
328 | return -1 - length;
329 | case 2:
330 | if (length < 0) {
331 | var elements = [];
332 | var fullArrayLength = 0;
333 | while ((length = readIndefiniteStringLength(majorType)) >= 0) {
334 | fullArrayLength += length;
335 | elements.push(readArrayBuffer(length));
336 | }
337 | var fullArray = new Uint8Array(fullArrayLength);
338 | var fullArrayOffset = 0;
339 | for (i = 0; i < elements.length; ++i) {
340 | fullArray.set(elements[i], fullArrayOffset);
341 | fullArrayOffset += elements[i].length;
342 | }
343 | return fullArray;
344 | }
345 | return readArrayBuffer(length);
346 | case 3:
347 | var utf16data = [];
348 | if (length < 0) {
349 | while ((length = readIndefiniteStringLength(majorType)) >= 0)
350 | appendUtf16data(utf16data, length);
351 | } else
352 | appendUtf16data(utf16data, length);
353 | return String.fromCharCode.apply(null, utf16data);
354 | case 4:
355 | var retArray;
356 | if (length < 0) {
357 | retArray = [];
358 | while (!readBreak())
359 | retArray.push(decodeItem());
360 | } else {
361 | retArray = new Array(length);
362 | for (i = 0; i < length; ++i)
363 | retArray[i] = decodeItem();
364 | }
365 | return retArray;
366 | case 5:
367 | var retObject = {};
368 | for (i = 0; i < length || length < 0 && !readBreak(); ++i) {
369 | var key = decodeItem();
370 | retObject[key] = decodeItem();
371 | }
372 | return retObject;
373 | case 6:
374 | return tagger(decodeItem(), length);
375 | case 7:
376 | switch (length) {
377 | case 20:
378 | return false;
379 | case 21:
380 | return true;
381 | case 22:
382 | return null;
383 | case 23:
384 | return undefined;
385 | default:
386 | return simpleValue(length);
387 | }
388 | }
389 | }
390 |
391 | var ret = decodeItem();
392 | if (offset !== data.byteLength)
393 | throw "Remaining bytes";
394 | return ret;
395 | }
396 |
397 | var obj = { encode: encode, decode: decode };
398 |
399 | if (typeof define === "function" && define.amd)
400 | define("cbor/cbor", obj);
401 | else if (!global.CBOR)
402 | global.cbor = obj;
403 |
404 | })(Copper);
405 |
--------------------------------------------------------------------------------
/content/coap/CoapMessage.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2015, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | *******************************************************************************/
31 | /**
32 | * \file
33 | * A wrapper for the different CoAP versions
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | //create a request/ack, received responses use parse()
39 | Copper.CoapMessage = function(type, code, uri, pl) {
40 |
41 | this.options = new Object();
42 | this.options[Copper.OPTION_CONTENT_FORMAT] = new Array(0, null);
43 | this.options[Copper.OPTION_MAX_AGE] = new Array(0, null);
44 | this.options[Copper.OPTION_PROXY_URI] = new Array(0, null);
45 | this.options[Copper.OPTION_PROXY_SCHEME] = new Array(0, null);
46 | this.options[Copper.OPTION_ETAG] = new Array(0, null);
47 | this.options[Copper.OPTION_URI_HOST] = new Array(0, null);
48 | this.options[Copper.OPTION_LOCATION_PATH] = new Array(0, null);
49 | this.options[Copper.OPTION_URI_PORT] = new Array(0, null);
50 | this.options[Copper.OPTION_LOCATION_QUERY] = new Array(0, null);
51 | this.options[Copper.OPTION_URI_PATH] = new Array(0, null);
52 | this.options[Copper.OPTION_OBSERVE] = new Array(0, null);
53 | this.options[Copper.OPTION_ACCEPT] = new Array(0, null);
54 | this.options[Copper.OPTION_IF_MATCH] = new Array(0, null);
55 | this.options[Copper.OPTION_URI_QUERY] = new Array(0, null);
56 | this.options[Copper.OPTION_BLOCK2] = new Array(0, null);
57 | this.options[Copper.OPTION_BLOCK1] = new Array(0, null);
58 | this.options[Copper.OPTION_SIZE2] = new Array(0, null);
59 | this.options[Copper.OPTION_SIZE1] = new Array(0, null);
60 | this.options[Copper.OPTION_IF_NONE_MATCH] = new Array(0, null);
61 |
62 | this.type = (type!==undefined) ? type : Copper.MSG_TYPE_CON;
63 | this.code = (code!==undefined) ? code : Copper.EMPTY;
64 |
65 | this.mid = -1;
66 | this.retries = 0;
67 | this.token = new Array(0);
68 |
69 | if (uri!==undefined) this.setUri( uri );
70 | if (pl!==undefined) {
71 | this.setPayload( pl );
72 | } else {
73 | this.payload = new Array(0);
74 | }
75 |
76 | return this;
77 | };
78 |
79 | Copper.CoapMessage.prototype = {
80 |
81 | version : Copper.VERSION,
82 |
83 | // message summary (e.g., for info/debug dumps)
84 | getSummary : function() {
85 | let ret = '';
86 | ret += ' Type: '+this.getType(true);
87 | ret += '\n Code: '+this.getCode(true);
88 | ret += '\n Message ID: '+this.getMID();
89 | ret += '\n Token: '+this.getToken();
90 | if (Object.keys(this.options).length > 0) {
91 | ret += '\n Options: '+this.getOptions(true);
92 | }
93 | if (this.getPayload().length > 0) {
94 | ret += '\n Payload: '+this.getPayload().length+' bytes';
95 | if (this.isPrintable(this.getContentFormat())) {
96 | ret += '\n'+Copper.bytes2str(this.getPayload());
97 | }
98 | }
99 | return ret;
100 | },
101 |
102 | // readable type
103 | getType : function(readable) {
104 | if (readable) {
105 | switch (parseInt(this.type)) {
106 | case Copper.MSG_TYPE_CON: return 'CON';
107 | case Copper.MSG_TYPE_NON: return 'NON';
108 | case Copper.MSG_TYPE_ACK: return 'ACK';
109 | case Copper.MSG_TYPE_RST: return 'RST';
110 | default: return 'unknown ('+this.type+')';
111 | }
112 | } else {
113 | return parseInt(this.type);
114 | }
115 | },
116 | setType : function(type) {
117 | this.type = type;
118 | },
119 |
120 | isConfirmable : function() {
121 | return this.type==Copper.MSG_TYPE_CON;
122 | },
123 |
124 | getOptionCount : function() {
125 | return this.optionCount;
126 | },
127 |
128 | getCode : function(readable) {
129 | if (readable) {
130 | return Copper.getCodeName(this.code);
131 | } else {
132 | return parseInt(this.code);
133 | }
134 | },
135 | setCode : function(code) {
136 | this.code = code;
137 | },
138 |
139 | isRequest: function() {
140 | return this.getCode()>=1 && this.getCode()<=31;
141 | },
142 | isResponse: function() {
143 | return this.getCode()>=64;
144 | },
145 |
146 | isSuccess: function() {
147 | return Math.floor(this.getCode() / 32) == 2;
148 | },
149 | isClientError: function() {
150 | return Math.floor(this.getCode() / 32) == 4;
151 | },
152 | isServerError: function() {
153 | return Math.floor(this.getCode() / 32) == 5;
154 | },
155 |
156 | getMID : function() {
157 | return this.mid;
158 | },
159 | setMID : function(id) {
160 | this.mid = id;
161 | },
162 |
163 | getToken : function() {
164 | // return token as string for easy use as object key
165 | return Copper.bytes2hex(this.token);
166 | },
167 | setToken : function(token) {
168 | if (!token) {
169 | token = new Array(0);
170 | } else if (token=='empty') {
171 | token = new Array(0);
172 | } else if (!Array.isArray(token)) {
173 | if (token.substr(0,2)=='0x') {
174 | token = Copper.hex2bytes(token);
175 | } else {
176 | token = Copper.str2bytes(token);
177 | }
178 | }
179 |
180 | while (token.length > Copper.TOKEN_LENGTH) {
181 | token.pop();
182 | Copper.logEvent('WARNING: Token must be 1-'+Copper.TOKEN_LENGTH+' bytes; cutting to '+Copper.TOKEN_LENGTH+' bytes]');
183 | }
184 |
185 | delete this.token;
186 | this.token = token;
187 | },
188 |
189 | // readable options list
190 | getOptions : function(asString) {
191 |
192 | if (asString) {
193 | let ret = '';
194 |
195 | for (let o in this.options) {
196 |
197 | if (Array.isArray(this.options[o][1])) {
198 |
199 | if (ret!='') ret += ', ';
200 |
201 | let name = Copper.getOptionName(o);
202 | let val = this.getOption(o);
203 | let info = this.options[o][0];
204 |
205 | switch (parseInt(o)) {
206 | case Copper.OPTION_BLOCK2:
207 | val = this.getBlock2Number();
208 | val += '/'+this.getBlock2More();
209 | val += '/'+this.getBlock2Size();
210 | break;
211 | case Copper.OPTION_BLOCK1:
212 | val = this.getBlock1Number();
213 | val += '/'+this.getBlock1More();
214 | val += '/'+this.getBlock1Size();
215 | break;
216 | }
217 |
218 | ret += name + ': ' + val;
219 | }
220 | }
221 |
222 | return ret;
223 | } else {
224 | let ret = new Array();
225 |
226 | for (let o in this.options) {
227 | if (Array.isArray(this.options[o][1])) {
228 | var name = Copper.getOptionName(o);
229 | var value = this.getOption(o);
230 | var info = this.options[o][0]+' byte' + (this.options[o][0]!=1 ? 's' : '');
231 |
232 | switch (parseInt(o)) {
233 | case Copper.OPTION_URI_PATH:
234 | case Copper.OPTION_LOCATION_PATH:
235 | value = '/' + value;
236 | break;
237 | case Copper.OPTION_CONTENT_FORMAT:
238 | info = value;
239 | value = Copper.getContentFormatName(value);
240 | break;
241 | case Copper.OPTION_ACCEPT:
242 | info = value;
243 | value = Copper.getContentFormatName(value);
244 | break;
245 | case Copper.OPTION_IF_NONE_MATCH:
246 | info = '';
247 | value = 'Set';
248 | break;
249 | case Copper.OPTION_BLOCK2:
250 | value = this.getBlock2Number();
251 | if (this.getBlock2More()) value += '+';
252 | value += ' ('+this.getBlock2Size()+' B/block)';
253 | break;
254 | case Copper.OPTION_BLOCK1:
255 | value = this.getBlock1Number();
256 | if (this.getBlock1More()) value += '+';
257 | value += ' ('+this.getBlock1Size()+' B/block)';
258 | break;
259 | }
260 |
261 | ret.push(new Array(name, value, info));
262 | }
263 | }
264 |
265 | return ret;
266 | }
267 | },
268 | // check if option is present
269 | isOption : function(optNumber) {
270 | if (this.options[optNumber]!==undefined && Array.isArray(this.options[optNumber][1])) {
271 | return true;
272 | } else {
273 | return false;
274 | }
275 | },
276 | // retrieve option
277 | getOptionLength : function(optNumber) {
278 | if (this.options[optNumber]!=null && this.options[optNumber][0]!=null) {
279 | return this.options[optNumber][0];
280 | } else {
281 | return -1;
282 | }
283 | },
284 | getOption : function(optNumber) {
285 | var opt = this.options[optNumber][1];
286 |
287 | // only set options are arrays
288 | if (!Array.isArray(opt)) {
289 | return null;
290 | }
291 |
292 | switch (parseInt(optNumber)) {
293 | // strings
294 | case Copper.OPTION_URI_HOST:
295 | case Copper.OPTION_URI_PATH:
296 | case Copper.OPTION_URI_QUERY:
297 | case Copper.OPTION_LOCATION_PATH:
298 | case Copper.OPTION_LOCATION_QUERY:
299 | case Copper.OPTION_PROXY_URI:
300 | case Copper.OPTION_PROXY_SCHEME:
301 | return Copper.bytes2str(opt);
302 | break;
303 |
304 | // integers
305 | case Copper.OPTION_URI_PORT:
306 | case Copper.OPTION_CONTENT_FORMAT:
307 | case Copper.OPTION_MAX_AGE:
308 | case Copper.OPTION_ACCEPT:
309 | case Copper.OPTION_IF_NONE_MATCH:
310 | case Copper.OPTION_OBSERVE:
311 | case Copper.OPTION_BLOCK2:
312 | case Copper.OPTION_BLOCK1:
313 | case Copper.OPTION_SIZE2:
314 | case Copper.OPTION_SIZE1:
315 | return Copper.bytes2int(opt);
316 |
317 | // byte arrays
318 | case Copper.OPTION_ETAG:
319 | case Copper.OPTION_IF_MATCH:
320 | return Copper.bytes2hex(opt);
321 | default:
322 | return Copper.bytes2hex(opt);
323 | }
324 | return null;
325 | },
326 |
327 | setOption : function(option, value) {
328 | switch (parseInt(option)) {
329 | // strings
330 | case Copper.OPTION_PROXY_URI:
331 | case Copper.OPTION_PROXY_SCHEME:
332 | case Copper.OPTION_LOCATION_PATH:
333 | case Copper.OPTION_LOCATION_QUERY:
334 | case Copper.OPTION_URI_HOST:
335 | case Copper.OPTION_URI_PATH:
336 | case Copper.OPTION_URI_QUERY:
337 | this.options[option][0] = value.length;
338 | this.options[option][1] = Copper.str2bytes(value);
339 | break;
340 |
341 | // byte arrays
342 | case Copper.OPTION_ETAG:
343 | case Copper.OPTION_IF_MATCH:
344 | this.options[option][0] = value.length;
345 | this.options[option][1] = value;
346 | break;
347 |
348 | // special arrays
349 | case -1:
350 | this.options[option][0] += 1;
351 | if (this.options[option][1]==null) this.options[option][1] = new Array(0);
352 | this.options[option][1][ this.options[option][0] ] = value;
353 | this.options[option][0] += 1;
354 | break;
355 |
356 | // integers
357 | case Copper.OPTION_CONTENT_FORMAT:
358 | case Copper.OPTION_MAX_AGE:
359 | case Copper.OPTION_URI_PORT:
360 | case Copper.OPTION_OBSERVE:
361 | case Copper.OPTION_ACCEPT:
362 | case Copper.OPTION_BLOCK2:
363 | case Copper.OPTION_BLOCK1:
364 | case Copper.OPTION_SIZE2:
365 | case Copper.OPTION_SIZE1:
366 | case Copper.OPTION_IF_NONE_MATCH:
367 | this.options[option][1] = Copper.int2bytes(value);
368 | this.options[option][0] = this.options[option][1].length;
369 | break;
370 |
371 | default:
372 | this.options[option] = new Array(value.length, value);
373 | Copper.logEvent("WARNING: Setting custom option '"+option+"': "+value);
374 | }
375 | },
376 |
377 |
378 | getContentFormat : function(readable) {
379 | var opt = this.getOption(Copper.OPTION_CONTENT_FORMAT); // integer
380 |
381 | if (opt==null) return null;
382 |
383 | if (readable) {
384 | return new Array(Copper.getContentFormatName(opt), opt);
385 | } else {
386 | return opt;
387 | }
388 | },
389 | setContentType : function(content) {
390 | if (content>0xFFFF) {
391 | Copper.logWarning('Ignoring Content-Format larger than 65535.');
392 | } else {
393 | this.setOption(Copper.OPTION_CONTENT_FORMAT, content);
394 | }
395 | },
396 |
397 | // Copper.OPTION_MAX_AGE:00+
398 | getMaxAge : function(readable) {
399 | var optLen = this.getOptionLength(Copper.OPTION_MAX_AGE);
400 | var opt = this.getOption(Copper.OPTION_MAX_AGE); // integer
401 |
402 | if (opt==null) return null;
403 |
404 | if (readable) {
405 |
406 | var ret = '';
407 | var time = opt;
408 |
409 | if (time==0) {
410 | ret += '0 ';
411 | } else {
412 | // split into weeks, days, hours, minutes, and seconds
413 | var s = time % 60;
414 | time = Math.floor(time/60);
415 | var m = time % 60;
416 | time = Math.floor(time/60);
417 | var h = time % 24;
418 | time = Math.floor(time/24);
419 | var d = time % 7;
420 | time = Math.floor(time/7);
421 | var w = time;
422 |
423 | var y = 0;
424 | if (w>104) var y = Math.round(1212424351/60.0/60.0/24.0/365.25*100.0)/100.0;
425 |
426 | // only print from largest to smallest given unit
427 | if (w) ret += w+'w ';
428 | if (d||(w&&(h||m||s))) ret += d+'d ';
429 | if (h||((w||d)&&(m||s))) ret += h+'h ';
430 | if (m||((w||d||h)&&s)) ret += m+'m ';
431 | if (s) ret += s+'s ';
432 | if (y) ret += '(~'+y+'y) ';
433 | }
434 |
435 | return new Array(ret.substring(0, ret.length-1), optLen+' byte(s)');
436 | } else {
437 | return opt;
438 | }
439 | },
440 | setMaxAge : function(age) {
441 | if (age>0xFFFFFFFF) {
442 | age = (0xFFFFFFFF & age);
443 | Copper.logWarning('Ignoring Max-Age larger than 2³²');
444 | }
445 | this.setOption(Copper.OPTION_MAX_AGE, age);
446 | },
447 |
448 | // Copper.OPTION_PROXY_URI:04+
449 | getProxyUri : function(readable) {
450 | return this.getOption(Copper.OPTION_PROXY_URI); // string
451 | },
452 | setProxyUri : function(proxy) {
453 | this.setOption(Copper.OPTION_PROXY_URI, proxy);
454 | },
455 |
456 | // Copper.OPTION_PROXY_URI:04+
457 | getProxyScheme : function(readable) {
458 | return this.getOption(Copper.OPTION_PROXY_SCHEME); // string
459 | },
460 | setProxyScheme : function(scheme) {
461 | this.setOption(Copper.OPTION_PROXY_SCHEME, scheme);
462 | },
463 |
464 | // Copper.OPTION_ETAG:00+
465 | getETag : function() {
466 | return this.getOption(Copper.OPTION_ETAG); // byte array
467 | },
468 | setETag : function(tag) {
469 |
470 | if (!Array.isArray(tag)) {
471 | Copper.logEvent('INFO: Converting ETag to byte array');
472 | if (tag.substr(0,2)=='0x') {
473 | tag = Copper.hex2bytes(tag);
474 | } else {
475 | tag = Copper.str2bytes(tag);
476 | }
477 | }
478 |
479 | if (tag.length>Copper.ETAG_LENGTH) {
480 | Copper.logWarning('Reducing ETag from '+tag.length+' to '+Copper.ETAG_LENGTH+' bytes.');
481 | tag = tag.slice(0, Copper.ETAG_LENGTH-1);
482 | }
483 |
484 | this.setOption(Copper.OPTION_ETAG, tag);
485 | },
486 |
487 | // Copper.OPTION_URI_HOST:04+ / Copper.OPTION_URI_AUTH:03*renamed
488 | getUriHost : function() {
489 | return this.getOption(Copper.OPTION_URI_HOST); // string
490 | },
491 | setUriHost : function(host) {
492 | this.setOption(Copper.OPTION_URI_HOST, host);
493 | },
494 | // Copper.OPTION_URI_PORT:04+
495 | getUriPort : function() {
496 | return this.getOption(Copper.OPTION_URI_PORT); // int
497 | },
498 | setUriPort : function(port) {
499 | this.setOption(Copper.OPTION_URI_PORT, port);
500 | },
501 | // multiple Copper.OPTION_URI_PATH:04+ / Copper.OPTION_URI_PATH:03+
502 | getUriPath : function() {
503 | // multiple Copper.OPTION_URI_PATH options should be concatinated during datagram parsing
504 | // TODO: maybe use a string array later
505 |
506 | return this.getOption(Copper.OPTION_URI_PATH); // string
507 | },
508 | // Copper.OPTION_URI_QUERY:03+
509 | getUriQuery : function() {
510 | return this.getOption(Copper.OPTION_URI_QUERY); // string
511 | },
512 | // convenience function
513 | getUri : function(readable) {
514 |
515 | let host = this.getUriHost();
516 | let port = this.getUriPort();
517 | let path = this.getUriPath();
518 | let query = this.getUriQuery();
519 |
520 | let uri = '';
521 | let decoded = 0;
522 | let multiple = null;
523 |
524 | if (host) {
525 | uri += 'coap://' + host;
526 | ++decoded;
527 | }
528 | if (port) {
529 | uri += ':' + port;
530 | ++decoded;
531 | }
532 | if (path) {
533 | uri += '/' + path;
534 | multiple = path.match(/\//g);
535 | decoded += 1 + (multiple!=null ? multiple.length : 0);
536 | }
537 | if (query) {
538 | uri += '?' + query;
539 | multiple = query.match(/&/g);
540 | decoded += 1 + (multiple!=null ? multiple.length : 0);
541 | }
542 |
543 | if (decoded<=0) return null;
544 |
545 | if (readable) {
546 | return new Array('Uri', uri, decoded+(decoded==1 ? ' option' : ' options'));
547 | } else {
548 | return uri;
549 | }
550 | },
551 | setUri : function(inputUri) {
552 |
553 | var uri = document.createElementNS("http://www.w3.org/1999/xhtml","a");
554 | /*
555 | * tag as parser:
556 | *
557 | * parser.protocol; // => "http:"
558 | * parser.hostname; // => "example.com"
559 | * parser.port; // => "3000"
560 | * parser.pathname; // => "/pathname/"
561 | * parser.search; // => "?search=test"
562 | * parser.hash; // => "#hash"
563 | * parser.host; // => "example.com:3000"
564 | */
565 | uri.href = inputUri;
566 |
567 | if (uri.hostname!='' // set
568 | && Copper.behavior.sendUriHost // enabled
569 | && !uri.hostname.match(/^[0-9]{1,3}(\.[0-9]{1,3}){3}$/) // no IPv4 literal
570 | && !uri.hostname.match(/^[0-9a-f]{0,4}(:?:[0-9a-f]{1,4})+$/i)) { // no IPv6 literal
571 | this.setOption(Copper.OPTION_URI_HOST, uri.hostname);
572 | }
573 | if (uri.pathname.length>1) {
574 | this.setOption(Copper.OPTION_URI_PATH, decodeURI(uri.pathname.substr(1)));
575 | }
576 | if (uri.search.length>1) {
577 | this.setOption(Copper.OPTION_URI_QUERY, uri.search.substr(1));
578 | }
579 | },
580 |
581 | // multiple Copper.OPTION_LOCATION_PATH:04+ / Copper.OPTION_LOCATION:03*renamed
582 | getLocationPath : function() {
583 | // multiple Copper.OPTION_LOCATION_PATH options should be concatinated during datagram parsing
584 | // TODO: maybe use a string array later
585 |
586 | return this.getOption(Copper.OPTION_LOCATION_PATH); // string
587 | },
588 | setLocationPath : function(path) {
589 | while (path.charAt(0)=='/') path = path.substr(1);
590 |
591 | this.setOption(Copper.OPTION_LOCATION_PATH, path);
592 | },
593 | // Copper.OPTION_LOCATION_QUERY:05+
594 | getLocationQuery : function() {
595 | return this.getOption(Copper.OPTION_LOCATION_QUERY); // string
596 | },
597 | setLocationQuery : function(query) {
598 | while (query.charAt(0)=='?') query = query.substr(1);
599 |
600 | this.setOption(Copper.OPTION_LOCATION_QUERY, query);
601 | },
602 | // convenience function
603 | getLocation : function(readable) {
604 | var optLen = this.getOptionLength(Copper.OPTION_LOCATION_PATH);
605 | var opt = this.getOption(Copper.OPTION_LOCATION_PATH); // string
606 |
607 | var optLen2 = 0;
608 |
609 | if (this.getOptionLength(Copper.OPTION_LOCATION_QUERY)) {
610 | opt += '?' + this.getOption(Copper.OPTION_LOCATION_QUERY);
611 | optLen2 = this.getOptionLength(Copper.OPTION_LOCATION_QUERY);
612 | }
613 |
614 | if (optLen+optLen2<=0) return null;
615 |
616 | if (readable) {
617 | var multiple = opt.match(/\/|&/g);
618 | var decoded = 1 + (multiple!=null ? multiple.length : 0) + (optLen2>0 ? 1 : 0);
619 | if (opt.charAt(0)!='/') opt = '/' + opt;
620 | return new Array(opt, decoded+(decoded==1 ? ' option' : ' options'));
621 | } else {
622 | if (opt) opt = '/'+opt;
623 | return opt;
624 | }
625 | },
626 |
627 | // Copper.OPTION_ACCEPT:07+
628 | getAccept : function() {
629 | return this.getOption(Copper.OPTION_ACCEPT); // integer
630 | },
631 | setAccept : function(content) {
632 | if (content>0xFFFF) {
633 | Copper.logWarning('Ignoring Accept Content-Format larger than 65535.');
634 | } else {
635 | this.setOption(Copper.OPTION_ACCEPT, content);
636 | }
637 | },
638 |
639 | // Copper.OPTION_IF_MATCH:07+
640 | getIfMatch : function() {
641 | return this.getOption(Copper.OPTION_IF_MATCH); // byte array
642 | },
643 | setIfMatch : function(tag) {
644 | if (!Array.isArray(tag)) {
645 | Copper.logEvent('INFO: Converting ETag to byte array');
646 | if (tag.substr(0,2)=='0x') {
647 | tag = Copper.hex2bytes(tag);
648 | } else {
649 | tag = Copper.str2bytes(tag);
650 | }
651 | }
652 |
653 | while (tag.length>Copper.ETAG_LENGTH) {
654 | Copper.logWarning('Reducing ETag from '+tag.length+' to '+Copper.ETAG_LENGTH+' bytes.');
655 | tag = tag.slice(0, Copper.ETAG_LENGTH-1);
656 | }
657 | this.setOption(Copper.OPTION_IF_MATCH, tag);
658 | },
659 |
660 | // Copper.OPTION_BLOCK2:06+ / Copper.OPTION_BLOCK:03+
661 | getBlock2 : function(readable) {
662 | var opt = this.getOption(Copper.OPTION_BLOCK2); // integer
663 |
664 | if (opt==null) return null;
665 |
666 | if (readable) {
667 | var ret = this.getBlock2Number();
668 | if (this.getBlock2More()) ret += '+';
669 | ret += ' ('+this.getBlock2Size()+' B/block)';
670 |
671 | return ret;
672 | } else {
673 | return opt;
674 | }
675 | },
676 | setBlock2 : function(num, size, more) {
677 |
678 | if (size!==undefined) {
679 |
680 | let block = num << 4;
681 |
682 | let szx = 0;
683 |
684 | // check for power of two and correct size
685 | if (!Copper.isPowerOfTwo(size)) {
686 | Copper.logEvent('INFO: Block2 size '+size+' not a power of two; using next smaller power.');
687 | }
688 | if (size<16) {
689 | size = 16;
690 | Copper.logEvent('INFO: Block2 size must be >=16; using 16.');
691 | }
692 | if (size>1024) {
693 | size = 1024;
694 | Copper.logEvent('INFO: Block2 size must be <=1024; using 1024.');
695 | }
696 |
697 | // size encoding
698 | size >>= 4;
699 | for (szx = 0; size; ++szx) size >>= 1;
700 | block |= (szx - 1);
701 |
702 | if (more!==undefined) {
703 | block |= more ? 0x08 : 0x00;
704 | }
705 |
706 | this.setOption(Copper.OPTION_BLOCK2, block);
707 |
708 | } else {
709 | this.setOption(Copper.OPTION_BLOCK2, num);
710 | }
711 | },
712 | // convenience functions for block option parts
713 | getBlock2Number : function() {
714 | return (this.getBlock2() >> 4);
715 | },
716 | getBlock2Size : function() {
717 | return (16 << (0x07 & this.getBlock2()));
718 | },
719 | getBlock2More : function() {
720 | return (parseInt(0x08 & this.getBlock2())!=0) ? 1 : 0;
721 | },
722 | getBlock2Offset : function() {
723 | return this.getBlock2Size() * (this.getBlock2Number() + 1);
724 | },
725 |
726 | // Copper.OPTION_BLOCK1:06+
727 | getBlock1 : function(readable) {
728 | var opt = this.getOption(Copper.OPTION_BLOCK1); // integer
729 |
730 | if (opt==null) return null;
731 |
732 | if (readable) {
733 | var ret = this.getBlock1Number();
734 | if (this.getBlock1More()) ret += '+';
735 | ret += ' ('+this.getBlock1Size()+' B/block)';
736 |
737 | return ret;
738 | } else {
739 | return opt;
740 | }
741 | },
742 | setBlock1 : function(num, size, more) {
743 | let block = num << 4;
744 | let szx = 0;
745 |
746 | // check for power of two and correct size
747 | if (!Copper.isPowerOfTwo(size)) {
748 | Copper.logEvent('INFO: Block1 size '+size+' not a power of two; using next smaller power.');
749 | }
750 | if (size<16) {
751 | size = 16;
752 | Copper.logEvent('INFO: Block1 size must be >=16; using 16.');
753 | }
754 | if (size>1024) {
755 | size = 1024;
756 | Copper.logEvent('INFO: Block1 size must be <=1024; using 1024.');
757 | }
758 |
759 | size >>= 4;
760 | for (szx = 0; size; ++szx) size >>= 1;
761 | block |= szx - 1;
762 | if (more) {
763 | block |= 0x08;
764 | }
765 |
766 | this.setOption(Copper.OPTION_BLOCK1, block);
767 | },
768 | // convenience functions for block option parts
769 | getBlock1Number : function() {
770 | return (this.getBlock1() >> 4);
771 | },
772 | getBlock1Size : function() {
773 | return (16 << (0x07 & this.getBlock1()));
774 | },
775 | getBlock1More : function() {
776 | return (0x08 & this.getBlock1()) ? 1 : 0;
777 | },
778 | getBlock1Offset : function() {
779 | return this.getBlock1Size() * (this.getBlock1Number() + 1);
780 | },
781 |
782 | // Copper.OPTION_SIZE2:18+ / Copper.OPTION_SIZE:09+
783 | getSize : function() {
784 | return this.getOption(Copper.OPTION_SIZE2); // integer
785 | },
786 | setSize2 : function(num) {
787 | if (num>0xFFFFFFFF) {
788 | Copper.logWarning('Ignoring Size2 larger than 2³²');
789 | } else {
790 | this.setOption(Copper.OPTION_SIZE2, num);
791 | }
792 | },
793 | // Copper.OPTION_SIZE1:18+
794 | getSize1 : function() {
795 | return this.getOption(Copper.OPTION_SIZE1); // integer
796 | },
797 | setSize1 : function(num) {
798 | if (num>0xFFFFFFFF) {
799 | Copper.logWarning('Ignoring Size1 larger than 2³²');
800 | } else {
801 | this.setOption(Copper.OPTION_SIZE1, num);
802 | }
803 | },
804 |
805 | // Copper.OPTION_IF_NONE_MATCH:07+
806 | getIfNoneMatch : function() {
807 | var opt = this.getOption(Copper.OPTION_IF_NONE_MATCH); // byte array
808 |
809 | return (opt==null ? null : 'none');
810 | },
811 | setIfNoneMatch : function() {
812 | // only set option with length 0 (int=0)
813 | this.setOption(Copper.OPTION_IF_NONE_MATCH, 0);
814 | },
815 |
816 | // Copper.OPTION_SUB_LIFETIME:draft-ietf-core-observe-00*renamed
817 | getObserve : function() {
818 | return this.getOption(Copper.OPTION_OBSERVE); // int
819 | },
820 | setObserve : function(num) {
821 | if (num> 0xFFFFFF) num = num % 0xFFFFFF;
822 | this.setOption(Copper.OPTION_OBSERVE, num);
823 | },
824 |
825 | setCustom : function(num, value) {
826 | if (Copper.getOptionName(num).match(/^Unknown/)) {
827 | if (value.substr(0,2)=='0x') {
828 | this.setOption(parseInt(num), Copper.hex2bytes(value));
829 | } else {
830 | this.setOption(parseInt(num), Copper.str2bytes(value));
831 | }
832 | } else {
833 | throw new Error('Cannot set '+Copper.getOptionName(num)+' as custom option');
834 | }
835 | },
836 |
837 | // payload functions
838 | getPayload : function() {
839 | return this.payload;
840 | },
841 | getPayloadText : function() {
842 | return Copper.bytes2str(this.payload);
843 | },
844 | setPayload : function(pl) {
845 | if (!Array.isArray(pl)) pl = Copper.str2bytes(pl);
846 | this.payload = pl;
847 | },
848 | appendPayload : function(pl) {
849 | this.payload = this.payload.concat(pl);
850 | },
851 | isPrintable : function(ct) {
852 | if (ct==null) ct = this.getContentFormat();
853 |
854 | switch (ct) {
855 | case Copper.CONTENT_TYPE_TEXT_PLAIN:
856 | case Copper.CONTENT_TYPE_TEXT_XML:
857 | case Copper.CONTENT_TYPE_TEXT_CSV:
858 | case Copper.CONTENT_TYPE_TEXT_HTML:
859 | case Copper.CONTENT_TYPE_APPLICATION_LINK_FORMAT:
860 | case Copper.CONTENT_TYPE_APPLICATION_XML:
861 | case Copper.CONTENT_TYPE_APPLICATION_RDF_XML:
862 | case Copper.CONTENT_TYPE_APPLICATION_SOAP_XML:
863 | case Copper.CONTENT_TYPE_APPLICATION_ATOM_XML:
864 | case Copper.CONTENT_TYPE_APPLICATION_XMPP_XML:
865 | case Copper.CONTENT_TYPE_APPLICATION_JSON:
866 | case Copper.CONTENT_TYPE_APPLICATION_CBOR:
867 | case Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_TEXT:
868 | case Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_JSON:
869 | case null:
870 | return true;
871 |
872 | case Copper.CONTENT_TYPE_IMAGE_GIF:
873 | case Copper.CONTENT_TYPE_IMAGE_JPEG:
874 | case Copper.CONTENT_TYPE_IMAGE_PNG:
875 | case Copper.CONTENT_TYPE_IMAGE_TIFF:
876 | case Copper.CONTENT_TYPE_AUDIO_RAW:
877 | case Copper.CONTENT_TYPE_VIDEO_RAW:
878 | case Copper.CONTENT_TYPE_APPLICATION_OCTET_STREAM:
879 | case Copper.CONTENT_TYPE_APPLICATION_EXI:
880 | case Copper.CONTENT_TYPE_APPLICATION_FASTINFOSET:
881 | case Copper.CONTENT_TYPE_APPLICATION_SOAP_FASTINFOSET:
882 | case Copper.CONTENT_TYPE_APPLICATION_X_OBIX_BINARY:
883 | case Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_TLV:
884 | case Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_OPAQUE:
885 | default:
886 | return false;
887 | }
888 | },
889 |
890 |
891 | // convert message into datagram bytes
892 | serialize : function() {
893 | return Copper.serialize();
894 | },
895 |
896 | // convert datagram bytes into message
897 | parse : function(datagram) {
898 | this.parse(datagram);
899 | },
900 |
901 | getRetries : function() {
902 | return this.retries;
903 | },
904 |
905 | incRetries : function() {
906 | ++this.retries;
907 | },
908 |
909 | // maybe more arguments needed
910 | respond : function(code, payload, format) {
911 | this.reply = new CoapMessage(Copper.MSG_TYPE_ACK, code, null, payload);
912 | this.reply.setMID(this.getMID());
913 | this.reply.setToken(this.getToken());
914 |
915 | if (format) this.reply.setContentType(format);
916 | },
917 |
918 | getReply : function() {
919 | return this.reply;
920 | }
921 | };
922 |
--------------------------------------------------------------------------------
/content/coap/CoapRFC7252.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2015, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | *******************************************************************************/
31 | /**
32 | * \file Implementation of RFC 7252
33 | *
34 | * \author Matthias Kovatsch
35 | */
36 |
37 | // Constants
38 | ////////////////////////////////////////////////////////////////////////////////
39 |
40 | Copper.__defineGetter__("VERSION", function() { return 1; });
41 | Copper.__defineGetter__("DEFAULT_PORT", function() { return 5683; });
42 | Copper.__defineGetter__("RESPONSE_TIMEOUT", function() { return 2000; }); // ms
43 | Copper.__defineGetter__("RESPONSE_RANDOM_FACTOR", function() { return 1.5; }); // ms
44 | Copper.__defineGetter__("MAX_RETRANSMIT", function() { return 4; });
45 | Copper.__defineGetter__("ETAG_LENGTH", function() { return 8; });
46 | Copper.__defineGetter__("TOKEN_LENGTH", function() { return 8; });
47 |
48 | Copper.__defineGetter__("MSG_TYPE_CON", function() { return 0; });
49 | Copper.__defineGetter__("MSG_TYPE_NON", function() { return 1; });
50 | Copper.__defineGetter__("MSG_TYPE_ACK", function() { return 2; });
51 | Copper.__defineGetter__("MSG_TYPE_RST", function() { return 3; });
52 |
53 | Copper.__defineGetter__("OPTION_IF_MATCH", function() { return 1; });
54 | Copper.__defineGetter__("OPTION_URI_HOST", function() { return 3; });
55 | Copper.__defineGetter__("OPTION_ETAG", function() { return 4; });
56 | Copper.__defineGetter__("OPTION_IF_NONE_MATCH", function() { return 5; });
57 | Copper.__defineGetter__("OPTION_URI_PORT", function() { return 7; });
58 | Copper.__defineGetter__("OPTION_LOCATION_PATH", function() { return 8; });
59 | Copper.__defineGetter__("OPTION_URI_PATH", function() { return 11; });
60 | Copper.__defineGetter__("OPTION_CONTENT_FORMAT", function() { return 12; });
61 | Copper.__defineGetter__("OPTION_MAX_AGE", function() { return 14; });
62 | Copper.__defineGetter__("OPTION_URI_QUERY", function() { return 15; });
63 | Copper.__defineGetter__("OPTION_ACCEPT", function() { return 17; });
64 | Copper.__defineGetter__("OPTION_LOCATION_QUERY", function() { return 20; });
65 | Copper.__defineGetter__("OPTION_PROXY_URI", function() { return 35; });
66 | Copper.__defineGetter__("OPTION_PROXY_SCHEME", function() { return 39; });
67 | Copper.__defineGetter__("OPTION_SIZE1", function() { return 60; });
68 |
69 | Copper.__defineGetter__("OPTION_OBSERVE", function() { return 6; });
70 |
71 | Copper.__defineGetter__("OPTION_BLOCK2", function() { return 23; });
72 | Copper.__defineGetter__("OPTION_BLOCK1", function() { return 27; });
73 | Copper.__defineGetter__("OPTION_SIZE2", function() { return 28; });
74 |
75 | Copper.__defineGetter__("EMPTY", function() { return 0; });
76 |
77 | Copper.__defineGetter__("GET", function() { return 1; });
78 | Copper.__defineGetter__("POST", function() { return 2; });
79 | Copper.__defineGetter__("PUT", function() { return 3; });
80 | Copper.__defineGetter__("DELETE", function() { return 4; });
81 | Copper.__defineGetter__("FETCH", function() { return 5; });
82 | Copper.__defineGetter__("PATCH", function() { return 6; });
83 | Copper.__defineGetter__("IPATCH", function() { return 7; });
84 |
85 | Copper.__defineGetter__("CODE_2_01_CREATED", function() { return 65; });
86 | Copper.__defineGetter__("CODE_2_02_DELETED", function() { return 66; });
87 | Copper.__defineGetter__("CODE_2_03_VALID", function() { return 67; });
88 | Copper.__defineGetter__("CODE_2_04_CHANGED", function() { return 68; });
89 | Copper.__defineGetter__("CODE_2_05_CONTENT", function() { return 69; });
90 | Copper.__defineGetter__("CODE_2_31_CONTINUE", function() { return 95; });
91 |
92 | Copper.__defineGetter__("CODE_4_00_BAD_REQUEST", function() { return 128; });
93 | Copper.__defineGetter__("CODE_4_01_UNAUTHORIZED", function() { return 129; });
94 | Copper.__defineGetter__("CODE_4_02_BAD_OPTION", function() { return 130; });
95 | Copper.__defineGetter__("CODE_4_03_FORBIDDEN", function() { return 131; });
96 | Copper.__defineGetter__("CODE_4_04_NOT_FOUND", function() { return 132; });
97 | Copper.__defineGetter__("CODE_4_05_METHOD_NOT_ALLOWED", function() { return 133; });
98 | Copper.__defineGetter__("CODE_4_06_NOT_ACCEPTABLE", function() { return 134; });
99 | Copper.__defineGetter__("CODE_4_08_REQUEST_ENTITY_INCOMPLETE", function() { return 136; });
100 | Copper.__defineGetter__("CODE_4_12_PRECONDITION_FAILED", function() { return 140; });
101 | Copper.__defineGetter__("CODE_4_13_REQUEST_ENTITY_TOO_LARGE", function() { return 141; });
102 | Copper.__defineGetter__("CODE_4_15_UNSUPPORTED_MEDIA_TYPE", function() { return 143; });
103 |
104 | Copper.__defineGetter__("CODE_5_00_INTERNAL_SERVER_ERROR", function() { return 160; });
105 | Copper.__defineGetter__("CODE_5_01_NOT_IMPLEMENTED", function() { return 161; });
106 | Copper.__defineGetter__("CODE_5_02_BAD_GATEWAY", function() { return 162; });
107 | Copper.__defineGetter__("CODE_5_03_SERVICE_UNAVAILABLE", function() { return 163; });
108 | Copper.__defineGetter__("CODE_5_04_GATEWAY_TIMEOUT", function() { return 164; });
109 | Copper.__defineGetter__("CODE_5_05_PROXYING_NOT_SUPPORTED", function() { return 165; });
110 |
111 | Copper.__defineGetter__("CONTENT_TYPE_TEXT_PLAIN", function() { return 0; });
112 | Copper.__defineGetter__("CONTENT_TYPE_TEXT_XML", function() { return 1; });
113 | Copper.__defineGetter__("CONTENT_TYPE_TEXT_CSV", function() { return 2; });
114 | Copper.__defineGetter__("CONTENT_TYPE_TEXT_HTML", function() { return 3; });
115 | Copper.__defineGetter__("CONTENT_TYPE_IMAGE_GIF", function() { return 21; }); // 03
116 | Copper.__defineGetter__("CONTENT_TYPE_IMAGE_JPEG", function() { return 22; }); // 03
117 | Copper.__defineGetter__("CONTENT_TYPE_IMAGE_PNG", function() { return 23; }); // 03
118 | Copper.__defineGetter__("CONTENT_TYPE_IMAGE_TIFF", function() { return 24; }); // 03
119 | Copper.__defineGetter__("CONTENT_TYPE_AUDIO_RAW", function() { return 25; }); // 03
120 | Copper.__defineGetter__("CONTENT_TYPE_VIDEO_RAW", function() { return 26; }); // 03
121 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_LINK_FORMAT", function() { return 40; });
122 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_XML", function() { return 41; });
123 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_OCTET_STREAM", function() { return 42; });
124 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_RDF_XML", function() { return 43; });
125 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_SOAP_XML", function() { return 44; });
126 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_ATOM_XML", function() { return 45; });
127 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_XMPP_XML", function() { return 46; });
128 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_EXI", function() { return 47; });
129 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_FASTINFOSET", function() { return 48; }); // 04
130 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_SOAP_FASTINFOSET", function() { return 49; }); // 04
131 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_JSON", function() { return 50; }); // 04
132 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_X_OBIX_BINARY", function() { return 51; });
133 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_CBOR", function() { return 60; }); // 04
134 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_TEXT", function() { return 1541; });
135 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_TLV", function() { return 1542; });
136 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_JSON", function() { return 1543; });
137 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_OPAQUE", function() { return 1544; });
138 |
139 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_THING_DESCRIPTION_JSON", function() { return 65200; });
140 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_BULLETIN_BOARD_JSON", function() { return 65201; });
141 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_LIGHTING_CONFIG_JSON", function() { return 65202; });
142 | Copper.__defineGetter__("CONTENT_TYPE_APPLICATION_LIGHTING_JSON", function() { return 65203; });
143 |
144 | Copper.__defineGetter__("WELL_KNOWN_RESOURCES", function() { return '/.well-known/core'; });
145 |
146 | //Registries
147 | ////////////////////////////////////////////////////////////////////////////////
148 |
149 | Copper.getCodeName = function(code) {
150 | switch (parseInt(code)) {
151 | // empty
152 | case 0: return 'EMPTY';
153 | // methods
154 | case Copper.GET: return 'GET';
155 | case Copper.POST: return 'POST';
156 | case Copper.PUT: return 'PUT';
157 | case Copper.DELETE: return 'DELETE';
158 | case Copper.FETCH: return 'FETCH';
159 | case Copper.PATCH: return 'PATCH';
160 | case Copper.IPATCH: return 'iPATCH';
161 | // response codes
162 | case Copper.CODE_2_01_CREATED: return '2.01 Created';
163 | case Copper.CODE_2_02_DELETED: return '2.02 Deleted';
164 | case Copper.CODE_2_03_VALID: return '2.03 Valid';
165 | case Copper.CODE_2_04_CHANGED: return '2.04 Changed';
166 | case Copper.CODE_2_05_CONTENT: return '2.05 Content';
167 | case Copper.CODE_2_31_CONTINUE: return '2.31 Continue';
168 | case Copper.CODE_4_00_BAD_REQUEST: return '4.00 Bad Request';
169 | case Copper.CODE_4_01_UNAUTHORIZED: return '4.01 Unauthorized';
170 | case Copper.CODE_4_02_BAD_OPTION: return '4.02 Bad Option';
171 | case Copper.CODE_4_03_FORBIDDEN: return '4.03 Forbidden';
172 | case Copper.CODE_4_04_NOT_FOUND: return '4.04 Not Found';
173 | case Copper.CODE_4_05_METHOD_NOT_ALLOWED: return '4.05 Method Not Allowed';
174 | case Copper.CODE_4_06_NOT_ACCEPTABLE: return '4.06 Not Acceptable';
175 | case Copper.CODE_4_08_REQUEST_ENTITY_INCOMPLETE: return '4.08 Request Entity Incomplete';
176 | case Copper.CODE_4_12_PRECONDITION_FAILED: return '4.12 Precondition Failed';
177 | case Copper.CODE_4_13_REQUEST_ENTITY_TOO_LARGE: return '4.13 Request Entity Too Large';
178 | case Copper.CODE_4_15_UNSUPPORTED_MEDIA_TYPE: return '4.15 Unsupported Content-Format';
179 | case Copper.CODE_5_00_INTERNAL_SERVER_ERROR: return '5.00 Internal Server Error';
180 | case Copper.CODE_5_01_NOT_IMPLEMENTED: return '5.01 Not Implemented';
181 | case Copper.CODE_5_02_BAD_GATEWAY: return '5.02 Bad Gateway';
182 | case Copper.CODE_5_03_SERVICE_UNAVAILABLE: return '5.03 Service Unavailable';
183 | case Copper.CODE_5_04_GATEWAY_TIMEOUT: return '5.04 Gateway Timeout';
184 | case Copper.CODE_5_05_PROXYING_NOT_SUPPORTED: return '5.05 Proxying Not Supported';
185 | // ...
186 | default: return Math.floor(code/32)+'.'+(code % 32)+' Unknown by Copper';
187 | }
188 | };
189 |
190 | Copper.getOptionName = function(number) {
191 | switch (parseInt(number)) {
192 | case Copper.OPTION_CONTENT_FORMAT: return 'Content-Format';
193 | case Copper.OPTION_MAX_AGE: return 'Max-Age';
194 | case Copper.OPTION_ACCEPT: return 'Accept';
195 |
196 | case Copper.OPTION_URI_HOST: return 'Uri-Host';
197 | case Copper.OPTION_URI_PORT: return 'Uri-Port';
198 | case Copper.OPTION_URI_PATH: return 'Uri-Path';
199 | case Copper.OPTION_URI_QUERY: return 'Uri-Query';
200 |
201 | case Copper.OPTION_LOCATION_PATH: return 'Location-Path';
202 | case Copper.OPTION_LOCATION_QUERY: return 'Location-Query';
203 |
204 | case Copper.OPTION_PROXY_URI: return 'Proxy-Uri';
205 | case Copper.OPTION_PROXY_SCHEME: return 'Proxy-Scheme';
206 |
207 | case Copper.OPTION_IF_MATCH: return 'If-Match';
208 | case Copper.OPTION_IF_NONE_MATCH: return 'If-None-Match';
209 | case Copper.OPTION_ETAG: return 'ETag';
210 |
211 | case Copper.OPTION_OBSERVE: return 'Observe';
212 |
213 | case Copper.OPTION_BLOCK2: return 'Block2';
214 | case Copper.OPTION_BLOCK1: return 'Block1';
215 |
216 | case Copper.OPTION_SIZE2: return 'Size2';
217 | case Copper.OPTION_SIZE1: return 'Size1';
218 |
219 | default: return 'Unknown '+number;
220 | }
221 | };
222 |
223 | Copper.getContentFormatName = function(type) {
224 | switch (type) {
225 | case Copper.CONTENT_TYPE_TEXT_PLAIN: return 'text/plain'; break;
226 | case Copper.CONTENT_TYPE_TEXT_XML: return 'text/xml'; break;
227 | case Copper.CONTENT_TYPE_TEXT_CSV: return 'text/csv'; break;
228 | case Copper.CONTENT_TYPE_TEXT_HTML: return 'text/html'; break;
229 | case Copper.CONTENT_TYPE_IMAGE_GIF: return 'image/gif'; break;
230 | case Copper.CONTENT_TYPE_IMAGE_JPEG: return 'image/jpeg'; break;
231 | case Copper.CONTENT_TYPE_IMAGE_PNG: return 'image/png'; break;
232 | case Copper.CONTENT_TYPE_IMAGE_TIFF: return 'image/tiff'; break;
233 | case Copper.CONTENT_TYPE_AUDIO_RAW: return 'audio/raw'; break;
234 | case Copper.CONTENT_TYPE_VIDEO_RAW: return 'video/raw'; break;
235 | case Copper.CONTENT_TYPE_APPLICATION_LINK_FORMAT: return 'application/link-format'; break;
236 | case Copper.CONTENT_TYPE_APPLICATION_XML: return 'application/xml'; break;
237 | case Copper.CONTENT_TYPE_APPLICATION_OCTET_STREAM: return 'application/octet-stream'; break;
238 | case Copper.CONTENT_TYPE_APPLICATION_RDF_XML: return 'application/rdf+xml'; break;
239 | case Copper.CONTENT_TYPE_APPLICATION_SOAP_XML: return 'application/soap+xml'; break;
240 | case Copper.CONTENT_TYPE_APPLICATION_ATOM_XML: return 'application/atom+xml'; break;
241 | case Copper.CONTENT_TYPE_APPLICATION_XMPP_XML: return 'application/xmpp+xml'; break;
242 | case Copper.CONTENT_TYPE_APPLICATION_EXI: return 'application/exi'; break;
243 | case Copper.CONTENT_TYPE_APPLICATION_FASTINFOSET: return 'application/fastinfoset'; break;
244 | case Copper.CONTENT_TYPE_APPLICATION_SOAP_FASTINFOSET: return 'application/soap+fastinfoset'; break;
245 | case Copper.CONTENT_TYPE_APPLICATION_JSON: return 'application/json'; break;
246 | case Copper.CONTENT_TYPE_APPLICATION_X_OBIX_BINARY: return 'application/x-obix-binary'; break;
247 | case Copper.CONTENT_TYPE_APPLICATION_CBOR: return 'application/cbor'; break;
248 | case Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_TEXT: return 'application/vnd.oma.lwm2m+text'; break;
249 | case Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_TLV: return 'application/vnd.oma.lwm2m+tlv'; break;
250 | case Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_JSON: return 'application/vnd.oma.lwm2m+json'; break;
251 | case Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_OPAQUE: return 'application/vnd.oma.lwm2m+opaque'; break;
252 | default: return 'unknown/unknown';
253 | }
254 | };
255 |
256 | // CoAP RFC 7252 implementation
257 | ////////////////////////////////////////////////////////////////////////////////
258 |
259 | Copper.serialize = function(message) {
260 | let byteArray = new Array();
261 | let tempByte = 0x00;
262 |
263 | // first byte: version, type, and token length
264 | tempByte = (0x03 & Copper.VERSION) << 6; // using const for sending packets
265 | tempByte |= (0x03 & message.type) << 4;
266 | tempByte |= (0x0F & message.token.length);
267 |
268 | byteArray.push(tempByte);
269 |
270 | // second byte: method or response code
271 | byteArray.push(0xFF & message.code);
272 |
273 | // third and forth byte: message ID (MID)
274 | byteArray.push(0xFF & (message.mid >>> 8));
275 | byteArray.push(0xFF & message.mid);
276 |
277 | for (let i in message.token) {
278 | byteArray.push(0xFF & message.token[i]);
279 | }
280 |
281 | // options
282 | message.optionCount = 0;
283 | let optNumber = 0;
284 |
285 | for (let optTypeIt in message.options) {
286 |
287 | if (!Array.isArray(message.options[optTypeIt][1])) {
288 | continue;
289 | } else {
290 |
291 | Copper.logEvent("SERIALIZE: Option "+Copper.getOptionName(optTypeIt));
292 |
293 | let splitOption = new Array();
294 | if (optTypeIt==Copper.OPTION_LOCATION_PATH ||
295 | optTypeIt==Copper.OPTION_LOCATION_QUERY ||
296 | optTypeIt==Copper.OPTION_URI_PATH ||
297 | optTypeIt==Copper.OPTION_URI_QUERY) {
298 |
299 | let separator = '/'; // 0x002F
300 | if (optTypeIt==Copper.OPTION_LOCATION_QUERY || optTypeIt==Copper.OPTION_URI_QUERY) {
301 | separator = '&'; // 0x0026
302 | }
303 |
304 | if (Copper.bytes2str(message.options[optTypeIt][1])!="") {
305 | let splitString = Copper.bytes2str(message.options[optTypeIt][1]).split(separator);
306 | for (let s in splitString) {
307 | // sending decoded segments on the wire
308 | splitOption.push(Copper.str2bytes(decodeURIComponent(splitString[s])));
309 | }
310 | }
311 | } else {
312 | splitOption.push(message.options[optTypeIt][1]);
313 | }
314 |
315 | while ((opt = splitOption.shift())) {
316 |
317 | let optDelta = optTypeIt - optNumber;
318 |
319 | let delta = Copper.optionNibble(optDelta);
320 | let len = Copper.optionNibble(opt.length);
321 |
322 | byteArray.push(0xFF & (delta<<4 | len));
323 |
324 | if (delta==13) {
325 | byteArray.push(optDelta-13);
326 | } else if (delta==14) {
327 | byteArray.push( (optDelta-269)>>>8 );
328 | byteArray.push( 0xFF & (optDelta-269) );
329 | }
330 | if (len==13) {
331 | byteArray.push(opt.length-13);
332 | } else if (len==14) {
333 | byteArray.push( (opt.length)>>>8 );
334 | byteArray.push( 0xFF & (opt.length-269) );
335 | }
336 |
337 | // add option value
338 | for (let i in opt) byteArray.push(opt[i]);
339 |
340 | message.optionCount++;
341 |
342 | optNumber = optTypeIt;
343 | }
344 | }
345 | }
346 |
347 | // option terminator
348 | if (message.payload.length>0) {
349 | byteArray.push(0xFF);
350 | }
351 |
352 | // serialize as string
353 | let packet = Copper.bytes2data(byteArray);
354 |
355 | // payload
356 | packet += Copper.bytes2data(message.payload);
357 |
358 | // finished
359 | return packet;
360 | };
361 |
362 | Copper.parse = function(packet) {
363 |
364 | Copper.logEvent('PACKET (hex): ' + packet.map(function(x){return x.toString(16).toUpperCase();}));
365 |
366 | // first byte: version, type, and option count
367 | let tempByte = packet.shift();
368 | let tokenLength = parseInt(0x0F & tempByte);
369 | let version = 0xFF & ((tempByte & 0xC0) >>> 6);
370 | if (version != Copper.VERSION) {
371 | throw new Error('Cannot parse CoAP version '+version);
372 | }
373 |
374 | // create the message
375 | var message = new Copper.CoapMessage( 0x03 & ((tempByte) >>> 4), packet.shift() );
376 |
377 | // third and forth byte: message ID (MID)
378 | message.mid = packet.shift() << 8;
379 | message.mid |= packet.shift();
380 |
381 | Copper.logEvent("PARSE: Token length = "+tokenLength);
382 | for (let i=0; i0) {
432 | optLen += 1 + message.options[optNumber][0];
433 | opt = message.options[optNumber][1].concat(separator).concat(opt);
434 | }
435 | }
436 |
437 | message.options[optNumber] = new Array(optLen, opt);
438 |
439 | } else {
440 | message.payload = packet;
441 | break;
442 | }
443 | }
444 |
445 | return message;
446 | };
447 |
448 |
449 | //Protocol helper functions
450 | ////////////////////////////////////////////////////////////////////////////////
451 |
452 | Copper.optionNibble = function(value) {
453 | if (value < 13) {
454 | return (0xFF & value);
455 | } else if (value <= 0xFF+13) {
456 | return 13;
457 | } else if (value <= 0xFFFF+269) {
458 | return 14;
459 | } else {
460 | throw new Error('Option delta/length larger than 65804 not allowed');
461 | }
462 | };
463 |
464 | Copper.isPowerOfTwo = function(i) {
465 | return ((i & (i-1))==0);
466 | };
467 |
468 | Copper.leadingZero = function(num, len) {
469 | if (!len) len = 2;
470 | num = ''+num;
471 | while (num.length 127) && (c < 2048)) {
505 | b.push(0xFF & ((c >> 6) | 192));
506 | b.push(0xFF & ((c & 63) | 128));
507 | } else {
508 | b.push(0xFF & ((c >> 12) | 224));
509 | b.push(0xFF & (((c >> 6) & 63) | 128));
510 | b.push(0xFF & ((c & 63) | 128));
511 | }
512 | }
513 | }
514 |
515 | return b;
516 | };
517 |
518 | Copper.bytes2str = function(b) {
519 |
520 | let str = '';
521 | var replaced = 0;
522 | for (let i=0; i= 32 && c < 127)) {
527 | str += String.fromCharCode(c);
528 | } else if(Copper.utf8 && c >= 192 && c < 224 && (i+1 < b.length) && (b[i+1] & 0xc0) == 0x80) {
529 | let c1 = c & 0x1f;
530 | let c2 = b[i+1] & 0x3F;
531 | str += String.fromCharCode((c1 << 6) | c2);
532 | i += 1;
533 | } else if (Copper.utf8 && c >= 224 && c < 240 && (i+2 < b.length) && (b[i+1] & 0xc0) == 0x80 && (b[i+2] & 0xc0) == 0x80) {
534 | let c1 = c & 0x0f;
535 | let c2 = b[i+1] & 0x3F;
536 | let c3 = b[i+2] & 0x3F;
537 | str += String.fromCharCode((c1 << 12) | (c2 << 6) | c3);
538 | i += 2;
539 | } else if (Copper.utf8 && c >= 240 && i+3 < b.length) {
540 | // 4-byte UTF-8
541 | str += String.fromCharCode(0xFFFD); // char '�'
542 | replaced++;
543 | i += 3;
544 | } else if (Copper.utf8 && c >= 128) {
545 | // Incomplete UTF-8 encoding
546 | str += String.fromCharCode(0xFFFD); // char '�'
547 | replaced++;
548 | } else {
549 | if (c < 32) {
550 | str += String.fromCharCode(0x2400 + c); // replacement character block
551 | } else {
552 | str += String.fromCharCode(0xFFFD); // char '�'
553 | replaced++;
554 | }
555 | // str += "\\x" + (c < 16 ? "0" : "") + c.toString(16);
556 | }
557 | }
558 | if (replaced > 0) {
559 | Copper.logEvent('bytes2str: replaced ' + replaced + ' invalid characters');
560 | }
561 | return str;
562 | };
563 |
564 | Copper.int2bytes = function(i) {
565 | var b = new Array(0);
566 | while (i>0) {
567 | b.unshift(0xFF & i);
568 | i >>>= 8;
569 | }
570 | return b;
571 | };
572 |
573 | Copper.bytes2int = function(b) {
574 | var i = 0;
575 | for (let k in b) {
576 | i = (i << 8) | b[k];
577 | }
578 | //convert to unsigned int
579 | return i>>>0;
580 | };
581 |
582 | Copper.hex2bytes = function(h) {
583 | var b = new Array();
584 | for (let i=h.length-2; i>0; i-=2) {
585 | b.unshift(parseInt(('0x'+h.substr(i,2)).replace(/xx/, 'x')));
586 | }
587 | return b;
588 | };
589 |
590 | Copper.bytes2hex = function(b) {
591 |
592 | if (!b || !Array.isArray(b) || b.length==0) {
593 | return 'empty';
594 | }
595 |
596 | var hex = '0x';
597 | for (let k in b) {
598 | if (b[k]!==undefined) {
599 | hex += Copper.leadingZero(b[k].toString(16).toUpperCase());
600 | } else {
601 | hex += '--';
602 | }
603 | }
604 |
605 | return hex;
606 | };
607 |
608 | Copper.str2hex = function(s) {
609 | var temp;
610 | if (s.substr(0,2)=='0x') {
611 | temp = Copper.hex2bytes(s);
612 | } else {
613 | temp = Copper.str2bytes(s);
614 | }
615 |
616 | return Copper.bytes2hex(temp);
617 | };
618 |
619 | Copper.float2bytes = function(value) {
620 | var bytes = 0;
621 | switch (value) {
622 | case Number.POSITIVE_INFINITY: bytes = 0x7F800000; break;
623 | case Number.NEGATIVE_INFINITY: bytes = 0xFF800000; break;
624 | case +0.0: bytes = 0x40000000; break;
625 | case -0.0: bytes = 0xC0000000; break;
626 | default:
627 | if (Number.isNaN(value)) { bytes = 0x7FC00000; break; }
628 |
629 | if (value <= -0.0) {
630 | bytes = 0x80000000;
631 | value = -value;
632 | }
633 |
634 | var exponent = Math.floor(Math.log(value) / Math.log(2));
635 | var significand = ((value / Math.pow(2, exponent)) * 0x00800000) | 0;
636 |
637 | exponent += 127;
638 | if (exponent >= 0xFF) {
639 | exponent = 0xFF;
640 | significand = 0;
641 | } else if (exponent < 0) exponent = 0;
642 |
643 | bytes = bytes | (exponent << 23);
644 | bytes = bytes | (significand & ~(-1 << 23));
645 | break;
646 | }
647 | return bytes;
648 | };
649 |
650 | Copper.double2bytes = function(value) {
651 |
652 | var hiWord = 0, loWord = 0;
653 | switch (value) {
654 | case Number.POSITIVE_INFINITY: hiWord = 0x7FF00000; break;
655 | case Number.NEGATIVE_INFINITY: hiWord = 0xFFF00000; break;
656 | case +0.0: hiWord = 0x40000000; break;
657 | case -0.0: hiWord = 0xC0000000; break;
658 | default:
659 | if (Number.isNaN(value)) { hiWord = 0x7FF80000; break; }
660 |
661 | if (value <= -0.0) {
662 | hiWord = 0x80000000;
663 | value = -value;
664 | }
665 |
666 | var exponent = Math.floor(Math.log(value) / Math.log(2));
667 | var significand = Math.floor((value / Math.pow(2, exponent)) * Math.pow(2, 52));
668 |
669 | loWord = significand & 0xFFFFFFFF;
670 | significand /= Math.pow(2, 32);
671 |
672 | exponent += 1023;
673 | if (exponent >= 0x7FF) {
674 | exponent = 0x7FF;
675 | significand = 0;
676 | } else if (exponent < 0) exponent = 0;
677 |
678 | hiWord = hiWord | (exponent << 20);
679 | hiWord = hiWord | (significand & ~(-1 << 20));
680 | break;
681 | }
682 |
683 | let bytes = new Array(0);
684 |
685 | bytes.unshift( loWord>>24 & 0xFF );
686 | bytes.unshift( loWord>>16 & 0xFF );
687 | bytes.unshift( loWord>>8 & 0xFF );
688 | bytes.unshift( loWord>>0 & 0xFF );
689 | bytes.unshift( hiWord>>24 & 0xFF );
690 | bytes.unshift( hiWord>>16 & 0xFF );
691 | bytes.unshift( hiWord>>8 & 0xFF );
692 | bytes.unshift( hiWord>>0 & 0xFF );
693 |
694 | return bytes;
695 | };
696 |
--------------------------------------------------------------------------------
/content/coap/TransactionHandler.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2015, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | *******************************************************************************/
31 | /**
32 | * \file
33 | * Code handling message transactions for the CoAP protocol
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | Copper.Transaction = function(myMessage, myTimer) {
39 | this.message = myMessage;
40 | this.timer = myTimer;
41 |
42 | this.rttStart = new Date().getTime();
43 |
44 | return this;
45 | };
46 | Copper.Transaction.prototype = {
47 | message : null,
48 | timer : null,
49 |
50 | rttStart : 0
51 | };
52 |
53 | Copper.TransactionHandler = function(myClient) {
54 |
55 | this.client = myClient;
56 | this.client.register( Copper.myBind(this, this.handle) );
57 |
58 | this.midGenerator = parseInt(Math.random()*0x10000);
59 |
60 | this.transactions = new Object();
61 | this.requests = new Object();
62 | this.registeredTokens = new Object();
63 | this.registeredMIDs = new Object();
64 | this.dupFilter = new Array();
65 | this.dupCache = new Object();
66 |
67 | return this;
68 | };
69 |
70 | Copper.TransactionHandler.prototype = {
71 |
72 | midGenerator : 0,
73 |
74 | client : null,
75 | defaultCB : null,
76 |
77 | transactions : null,
78 |
79 | requests : null,
80 | registeredTokens : null,
81 | registeredMIDs : null,
82 |
83 | dupFilter : null,
84 | dupCache : null,
85 |
86 | registerCallback : function(myCB) {
87 | this.defaultCB = myCB;
88 | },
89 |
90 | nextMID : function() {
91 | this.midGenerator = (this.midGenerator+1) % 0x10000;
92 | //return Math.pow(2, this.midGenerator) % 419;
93 | return this.midGenerator;
94 | },
95 |
96 | stopRetransmission : function(token) {
97 | for (let mid in this.transactions) {
98 | if (this.transactions[mid].message.getToken()==token) {
99 | if (this.transactions[mid].timer) {
100 | window.clearTimeout(this.transactions[mid].timer);
101 | }
102 | Copper.logEvent('INFO: Stopping MID '+mid);
103 | delete this.transactions[mid];
104 | }
105 | }
106 | },
107 |
108 | stopRetransmissions : function() {
109 | for (let mid in this.transactions) {
110 | if (this.transactions[mid].timer) {
111 | window.clearTimeout(this.transactions[mid].timer);
112 | }
113 | Copper.logEvent('INFO: Stopping MID '+mid);
114 | delete this.transactions[mid];
115 | }
116 | },
117 |
118 | cancelTransactions : function() {
119 | this.stopRetransmissions();
120 |
121 | this.requests = new Object();
122 | this.registeredTokens = new Object();
123 | this.registeredMIDs = new Object();
124 |
125 | Copper.observer.clean();
126 | },
127 |
128 | registerToken : function(token, cb) {
129 | Copper.logEvent('INFO: Registering token '+token);
130 | this.registeredTokens[token] = cb;
131 | },
132 |
133 | deRegisterToken : function(token) {
134 | if (this.registeredTokens[token]) {
135 | Copper.logEvent('INFO: Deregistering token '+token);
136 | delete this.registeredTokens[token];
137 | }
138 | for (let i in this.registeredTokens) {
139 | if (this.registeredTokens[i]) Copper.logEvent(' '+i);
140 | }
141 | },
142 |
143 | send : function(message, reqCB) {
144 |
145 | if (this.client.ended) return;
146 |
147 | // set MID for message
148 | if (message.getMID()==-1) {
149 | message.setMID( this.nextMID() );
150 | }
151 |
152 | var that = this; // coping with the JavaScript scope...
153 | var timer = null;
154 |
155 | // store reliable transaction
156 | if (message.isConfirmable()) {
157 | if (Copper.behavior.retransmissions) {
158 | // schedule resend without RANDOM_FACTOR since we already have human jitter
159 | timer = window.setTimeout(function(){Copper.myBind(that,that.resend(message.getMID()));}, Copper.RESPONSE_TIMEOUT);
160 | } else {
161 | // also schedule 'not responding' timeout when retransmissions are disabled
162 | timer = window.setTimeout(function(){Copper.myBind(that,that.resend(message.getMID()));}, 16000); // 16 seconds
163 | }
164 | Copper.logEvent('INFO: Storing MID '+ message.getMID());
165 | this.transactions[message.getMID()] = new Copper.Transaction(message, timer);
166 | }
167 |
168 | // store request callback through token matching
169 | if (message.isRequest()) {
170 |
171 | while (this.requests[message.getToken()]!=null && this.registeredTokens[message.getToken()]==null) {
172 | Copper.logEvent('INFO: Default token already in use');
173 | message.setToken([parseInt(Math.random()*0x100), parseInt(Math.random()*0x100)]);
174 | }
175 | this.requests[message.getToken()] = reqCB===undefined ? this.defaultCB : reqCB;
176 |
177 | // also save callback by MID
178 | this.registeredMIDs[message.getMID()] = this.requests[message.getToken()];
179 |
180 | // store notification (needed for NON)
181 | } else if (message.isResponse() && message.getObserve()!=null) {
182 | this.registeredMIDs[message.getMID()] = reqCB;
183 |
184 | // store ping
185 | } else if (message.getType()==Copper.MSG_TYPE_CON && message.getCode()==0) {
186 | this.registeredMIDs[message.getMID()] = reqCB;
187 | }
188 |
189 | Copper.logMessage(message, true);
190 |
191 | this.client.send( Copper.serialize(message) );
192 | },
193 |
194 | resend : function(mid) {
195 | if (Copper.behavior.retransmissions && this.transactions[mid]!==undefined && (this.transactions[mid].message.getRetries() < Copper.MAX_RETRANSMIT)) {
196 |
197 | var that = this;
198 | this.transactions[mid].message.incRetries();
199 |
200 | var timeout = Copper.RESPONSE_TIMEOUT*Math.pow(2,this.transactions[mid].message.getRetries());
201 | this.transactions[mid].timer = window.setTimeout(function(){Copper.myBind(that,that.resend(mid));}, timeout);
202 |
203 | Copper.logMessage(this.transactions[mid].message, true);
204 |
205 | this.client.send( Copper.serialize(this.transactions[mid].message) );
206 |
207 | Copper.popup(Copper.hostname+':'+Copper.port, 'Re-transmitting message '+mid+' ('+this.transactions[mid].message.getRetries()+'/'+Copper.MAX_RETRANSMIT+')');
208 |
209 | } else {
210 | Copper.logWarning('Message ' + mid + ' timed out.');
211 | this.cancelTransactions();
212 | delete this.transactions[mid];
213 | }
214 | },
215 |
216 | handle : function(datagram) {
217 | // parse byte message to CoAP message
218 | let message = Copper.parse(datagram);
219 |
220 | Copper.logMessage(message, false);
221 |
222 | if (this.transactions[message.getMID()]) {
223 | // calculate round trip time
224 | var ms = (new Date().getTime() - this.transactions[message.getMID()].rttStart);
225 | message.getRTT = function() { return ms; };
226 | Copper.logEvent('INFO: MID ' +message.getMID() + ' has RTT ' + ms + ' ms');
227 |
228 | // stop retransmission
229 | Copper.logEvent('INFO: Closing MID ' + message.getMID() );
230 | if (this.transactions[message.getMID()].timer) window.clearTimeout(this.transactions[message.getMID()].timer);
231 |
232 | // clear transaction
233 | delete this.transactions[message.getMID()];
234 |
235 | // filter duplicates
236 | } else if (this.dupFilter.indexOf(message.getMID()) != -1) {
237 |
238 | if (message.getType()==Copper.MSG_TYPE_CON) {
239 | var reply = this.dupCache[message.getMID()];
240 | if (reply) {
241 | Copper.logEvent('INFO: Replying to duplicate (Message ID: '+message.getMID()+')');
242 | this.send(reply);
243 | } else if (message.getType()==Copper.MSG_TYPE_CON) {
244 | Copper.logEvent('INFO: Acknowledging duplicate (Message ID: '+message.getMID()+')');
245 | this.ack(message.getMID());
246 | }
247 | } else {
248 | Copper.logEvent('INFO: Ignoring duplicate (Message ID: '+message.getMID()+')');
249 | }
250 | return;
251 | }
252 |
253 | // callback for message
254 | var callback = null;
255 |
256 | // Requests
257 | if (message.isRequest()) {
258 |
259 | // no server role in this add-on
260 | callback = null;
261 |
262 | // Responses
263 | } else if (message.isResponse()) {
264 | // request matching by token
265 | if (this.requests[message.getToken()]) {
266 |
267 | // separate response
268 | if (!this.registeredMIDs[message.getMID()]) {
269 | if (message.getType()==Copper.MSG_TYPE_CON || message.getType()==Copper.MSG_TYPE_NON) {
270 | Copper.logEvent('INFO: Separate response as implicit acknowledgement for token: '+message.getToken() );
271 | // stop retransmission if implicit acknowledgement
272 | this.stopRetransmission(message.getToken());
273 | }
274 | }
275 |
276 | callback = this.requests[message.getToken()];
277 |
278 | delete this.requests[message.getToken()];
279 | delete this.registeredMIDs[message.getMID()];
280 |
281 | // check registered Tokens, e.g., subscriptions
282 | } else if (this.registeredTokens[message.getToken()]) {
283 | callback = this.registeredTokens[message.getToken()];
284 |
285 | // error
286 | } else {
287 | Copper.logEvent('INFO: Received unknown token');
288 |
289 | if (Copper.behavior.showUnknown) {
290 | // hack for additional info
291 | message.getCopperCode = function() { return 'Unknown token'; };
292 | this.defaultCB(message);
293 | }
294 |
295 | if (Copper.behavior.rejectUnknown && (message.getType()==Copper.MSG_TYPE_CON || message.getType()==Copper.MSG_TYPE_NON)) {
296 | Copper.logEvent('INFO: Rejecting unknown token');
297 | this.reset(message.getMID());
298 | }
299 |
300 | return;
301 | }
302 |
303 | // ACK separate response before handler (which might elicit a new request)
304 | if (message.getType()==Copper.MSG_TYPE_CON) {
305 | this.ack(message.getMID());
306 | }
307 |
308 | // Empty messages
309 | } else {
310 | callback = this.registeredMIDs[message.getMID()];
311 |
312 | delete this.registeredMIDs[message.getMID()];
313 |
314 | // separate response
315 | if (message.getType()==Copper.MSG_TYPE_ACK && message.getCode()==Copper.EMPTY) {
316 | message.getCopperCode = function() { return 'Separate response inbound'; };
317 | }
318 | }
319 |
320 | // callback might set reply for message used by deduplication
321 | if (callback) {
322 | try {
323 | callback(message);
324 | } catch (ex) {
325 | ex.message = 'Message callback failed:\n' + ex.message;
326 | Copper.logError(ex);
327 | }
328 | }
329 |
330 | // piggyback response or ack received CON messages
331 | if (message.reply) {
332 | this.send(message.reply);
333 | }
334 |
335 | // add to duplicates filter
336 | if (message.getType()!=Copper.MSG_TYPE_RST) {
337 | this.dupFilter.unshift(message.getMID());
338 | if (message.reply) this.dupCache[message.getMID()] = message.reply;
339 | if (this.dupFilter.length>10) {
340 | delete this.dupCache[this.dupFilter.pop()];
341 | }
342 | }
343 | },
344 |
345 | ack : function(mid) {
346 | var ack = new Copper.CoapMessage(Copper.MSG_TYPE_ACK);
347 | ack.setMID( mid );
348 | Copper.popup(Copper.hostname+':'+Copper.port, 'Sending ACK for message '+mid);
349 | this.send( ack );
350 | },
351 |
352 | reset : function(mid) {
353 | var rst = new Copper.CoapMessage(Copper.MSG_TYPE_RST);
354 | rst.setMID( mid );
355 | Copper.popup(Copper.hostname+':'+Copper.port, 'Sending RST for message '+mid);
356 | this.send( rst );
357 | },
358 |
359 | shutdown : function() {
360 | this.client.shutdown();
361 | }
362 | };
363 |
--------------------------------------------------------------------------------
/content/coap/UdpClient.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2015, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | *******************************************************************************/
31 | /**
32 | * \file
33 | * Code handling the UDP communication for the CoAP protocol
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | /*
39 | * FIXME: inputStream does not separate single datagrams.
40 | * Thus, increased traffic results in merged datagrams, i.e., one or more datagrams are added to the payload of the first one.
41 | * A workaround will probably need native code to provide a datagram handler (transport-service) that pipes them to/from Firefox.
42 | */
43 |
44 | Copper.UdpClient = function(remoteHost, remotePort) {
45 |
46 | // createTransport requires plain IPv6 address
47 | this.host = remoteHost.replace(/\[/,'').replace(/\]/,'');
48 | this.port = remotePort;
49 |
50 | this.transportService = Components.classes["@mozilla.org/network/socket-transport-service;1"].getService(Components.interfaces.nsISocketTransportService);
51 | this.pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].createInstance(Components.interfaces.nsIInputStreamPump);
52 |
53 | this.socket = this.transportService.createTransport(["udp"], 1, this.host, this.port, null);
54 |
55 | this.outputStream = this.socket.openOutputStream(0, 0, 0);
56 | this.inputStream = this.socket.openInputStream(0, 0, 0); // 1,0,0 = OPEN_BLOCKING
57 |
58 | this.pump.init(this.inputStream, -1, -1, 0, 0, false);
59 | this.pump.asyncRead(this, null);
60 |
61 | this.localAddr = null;
62 | this.callback = null;
63 | this.lastSend = null;
64 | this.ended = false;
65 |
66 | return this;
67 | };
68 |
69 | Copper.UdpClient.prototype = {
70 |
71 | register : function(myCB) {
72 | this.callback = myCB;
73 | },
74 |
75 | // stream observer functions
76 | onStartRequest : function(request, context) {
77 | // do nothing
78 | },
79 |
80 | onStopRequest : function(request, context, status) {
81 | if (!this.ended) {
82 | this.shutdown();
83 | throw new Error('Host/network unreachable');
84 | } else {
85 | Copper.logWarning('Illegal UdpClient state');
86 | }
87 | },
88 |
89 | onDataAvailable : function(request, context, inputStream, offset, count) {
90 | try {
91 | let sis = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
92 | sis.init(inputStream);
93 |
94 | var byteArray = new Array();
95 | for (let i=0; i4) {
101 | Copper.logEvent('UDP: Concatenated 4 + ' + (count-4) + ' bytes');
102 | if (this.callback) this.callback(byteArray);
103 | // reset for next datagram
104 | i = -1; // i++ still coming
105 | count -= 4;
106 | byteArray = new Array();
107 | }
108 | }
109 |
110 | Copper.logEvent('UDP: Received ' + byteArray.length + ' bytes');
111 |
112 | if (this.callback) this.callback(byteArray);
113 |
114 |
115 | } catch (ex) {
116 | Copper.logError(ex);
117 | }
118 | },
119 |
120 | // UdpClient functions
121 | shutdown : function() {
122 | // will also trigger onStopRequest()
123 | this.ended = true;
124 | this.outputStream.close();
125 | this.inputStream.close();
126 | this.socket.close(0);
127 | },
128 |
129 | send : function(datagram) {
130 |
131 | if (this.ended) return;
132 |
133 | // the transport API also concatenates outgoing datagrams when sent too quickly
134 | let since = new Date() - this.lastSend;
135 | if (since<30) {
136 | var that = this;
137 | window.setTimeout(
138 | function() { Copper.myBind(that,that.send(datagram)); },
139 | 30-since);
140 | return;
141 | }
142 |
143 | this.lastSend = new Date();
144 |
145 | try {
146 | this.outputStream.write(datagram, datagram.length);
147 |
148 | Copper.logEvent('UDP: Sent ' + datagram.length + ' bytes');
149 | } catch (ex) {
150 | Copper.logError(ex);
151 | }
152 | },
153 |
154 | getAddr : function() {
155 |
156 | try {
157 | this.localAddr = this.socket.getScriptableSelfAddr();
158 | return this.localAddr;
159 | } catch (ex) {
160 | return null;
161 | }
162 | },
163 |
164 | setTimeout : function(time) {
165 | this.socket.setTimeout(this.socket.TIMEOUT_READ_WRITE, time);
166 | }
167 | };
168 |
--------------------------------------------------------------------------------
/content/launcher.xul:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
34 |
35 |
68 |
--------------------------------------------------------------------------------
/content/namespace.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 | /**
32 | * \file
33 | * Namespace definition for the Copper CoAP Browser
34 | *
35 | * \author Matthias Kovatsch \author
36 | */
37 |
38 | /**
39 | * Copper namespace.
40 | */
41 | if ("undefined" == typeof(Copper)) {
42 | var Copper = {};
43 | };
44 |
--------------------------------------------------------------------------------
/content/options.xul:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/content/overlay.xul:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
34 |
35 |
36 |
37 |
39 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
57 |
58 |
59 |
60 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/defaults/preferences/prefs.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich.
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the Institute nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * This file is part of the Copper (Cu) CoAP user-agent.
30 | ******************************************************************************/
31 |
32 | pref("extensions.copper.first-run", true);
33 | pref("extensions.copper.view-tree", true);
34 | pref("extensions.copper.view-debug", true);
35 | pref("extensions.copper.view-log", true);
36 | pref("extensions.copper.enable-etch", true);
37 | pref("extensions.copper.encode-utf-8", true);
38 | pref("extensions.copper.behavior.auto-discover", false);
39 | pref("extensions.copper.behavior.requests", "con");
40 | pref("extensions.copper.behavior.retransmissions", true);
41 | pref("extensions.copper.behavior.send-duplicates", false);
42 | pref("extensions.copper.behavior.show-unknown", false);
43 | pref("extensions.copper.behavior.reject-unknown", true);
44 | pref("extensions.copper.behavior.send-uri-host", false);
45 | pref("extensions.copper.behavior.send-size1", false);
46 | pref("extensions.copper.behavior.block-size", 64);
47 | pref("extensions.copper.behavior.observe-token", true);
48 | pref("extensions.copper.behavior.observe-cancellation", "lazy");
49 | pref("extensions.copper.onload-action", "");
50 | pref("extensions.copper.debug.options-enabled", false);
51 | pref("extensions.copper.debug.options.content-format", "");
52 | pref("extensions.copper.debug.options.max-age", "");
53 | pref("extensions.copper.debug.options.proxy-uri", "");
54 | pref("extensions.copper.debug.options.proxy-scheme", false);
55 | pref("extensions.copper.debug.options.etag", "");
56 | pref("extensions.copper.debug.options.uri-host", "");
57 | pref("extensions.copper.debug.options.location-path", "");
58 | pref("extensions.copper.debug.options.uri-port", "");
59 | pref("extensions.copper.debug.options.location-query", "");
60 | pref("extensions.copper.debug.options.observe", "");
61 | pref("extensions.copper.debug.options.token", "");
62 | pref("extensions.copper.debug.options.accept", "");
63 | pref("extensions.copper.debug.options.if-match", "");
64 | pref("extensions.copper.debug.options.block2", "");
65 | pref("extensions.copper.debug.options.block1", "");
66 | pref("extensions.copper.debug.options.size2", "");
67 | pref("extensions.copper.debug.options.size1", "");
68 | pref("extensions.copper.debug.options.block-auto", true);
69 | pref("extensions.copper.debug.options.if-none-match", false);
70 | pref("extensions.copper.debug.options.custom-number", "");
71 | pref("extensions.copper.debug.options.custom-value", "");
72 | pref("extensions.copper.plugtest.menu", false);
73 | pref("extensions.copper.plugtest.proxy", false);
74 | pref("extensions.copper.plugtest.origin-server", "");
75 | pref("extensions.copper.plugtest.current", 0);
76 | pref("extensions.copper.window.view-tree-box", "220");
77 | pref("extensions.copper.window.view-tree-state", "open");
78 | pref("extensions.copper.window.view-tree-scroll", "0");
79 | pref("extensions.copper.window.view-log-box", "160");
80 | pref("extensions.copper.window.view-log-state", "open");
81 | pref("extensions.copper.window.view-debug-box", "216");
82 | pref("extensions.copper.window.view-debug-state", "open");
83 | pref("extensions.copper.window.view-tab-index", 0);
84 |
--------------------------------------------------------------------------------
/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | copper@vs.inf.ethz.ch
6 | Copper (Cu)
7 | 1.1.0pre
8 | 2
9 | false
10 | true
11 | Matthias Kovatsch, ETH Zurich
12 | Copper (Cu) CoAP user-agent for Firefox. It installs a handler for the 'coap' URI scheme and allows users to browse and interact with Internet of Things devices.
13 | http://people.inf.ethz.ch/mkovatsc/
14 | chrome://copper/skin/Cu_64.png
15 | chrome://copper/content/options.xul
16 |
17 |
18 |
19 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
20 | 4.0
21 | 52.*
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------