├── .gitignore
├── HttpRequester.iml
├── README.md
├── build
├── build.xml
└── launchFFSavePID.sh
└── src
├── chrome.manifest
├── chrome
└── icons
│ └── default
│ ├── httprequester-window.ico
│ └── httprequester-window.xpm
├── content
├── Base64.js
├── GoogleLogin.js
├── HTTP.js
├── Response.js
├── about.xul
├── google-login.xul
├── httprequester-window.xul
├── httprequester.js
├── loadRequest.js
├── loadRequest.xul
├── overlay.js
├── overlay.xul
├── progress.xul
├── request-entry.js
└── request-entry.xul
├── defaults
└── preferences
│ └── defaults.js
├── install.rdf
├── readme.txt
└── skin
├── default.css
├── httprequester.png
├── httprequester16x16.png
└── overlay.css
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/HttpRequester.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | HttpRequester
2 | =============
3 | HttpRequester is a tool for Firefox for easily making HTTP requests (GET/PUT/POST/DELETE), viewing the responses, and keeping a history of transactions.
4 |
5 | This tool is useful when doing web or REST development, or when you need to make HTTP requests that are not easily done via the browser (PUT/POST/DELETE).
6 |
7 | This is based off of Alex Milowski's excellent Poster addon, with a large focus on keeping a history of transactions, allowing you to go back and review, re-execute, load, and save HTTP requests.
8 |
9 | Developed by Tom Mutdosch
10 |
11 | Distributed under the BSD License
12 | http://www.opensource.org/licenses/bsd-license.php
13 |
14 | Overview
15 |
16 |
View responses in an embedded browser, or in plain text (with an option to pretty-format XML/JSON).
17 |
A history of transactions is recorded (and kept across sessions). You can view past requests, and re-execute them. Selecting a transaction in the History list will show the full request/response.
18 |
For each transaction in the list, the request and response are shown, as well as the Elapsed Time and Content-Length (The value used is the Content-Length response header if available, and the size of the response body otherwise.)
19 |
Each column in the history list is resizable and re-orderable and can be hidden via the column picker. The ordering and width of each column are persisted.
20 |
Double-clicking a row in the history will show you a raw text version of the request and response
21 |
You can edit raw requests by double-clicking a row in the history list, or clicking the Edit Raw Request button. This is useful for easily viewing the request all at once, or for making quick tweaks to a previous request, such as adding or changing headers. This is
22 | the same behavior as double-clicking a transaction in the transaction history list.
23 |
Recent URLs, header names, and content types are remembered across sessions, and can easily be selected from drop-down lists.
24 |
25 | Usage
26 |
27 |
HttpRequester can be opened via the Toolbar button (the green/red arrow icon), or opened via the Tools menu. Alternatively the shortcut CTRL-ALT-P will bring up HttpRequester.
28 |
You can press the Delete Request button to remove a selected transaction from history list. (You can also hit the Delete key)
29 |
You can copy a request/response to clipboard for pasting into bug report, etc. You can also copy existing requests from the clipboard by clicking the Paste Request button, and then executing the request. Select multiple requests at once by holding down CTRL while selecting another request from the list.
30 |
Press the key to close the HttpRequester window
31 |
Save and load stored requests: To save a request, click on a request in the history list and click Save Request. You can optionally give the request a name.
32 |
To load a request, click on Load Request - that will bring up a list of all saved requests. You can select any request to load it into your history to view it, or you can click the Execute button to execute it immediately.
33 |
34 |
35 |
36 | Advanced Preferences: (via about:config):
37 | Increasing number of items in history
38 | extensions.httprequester.maxhistory - maximum number of requests to keep
39 | extensions.httprequester.url.maxhistory - maximum number of URLs to keep
40 | extensions.httprequester.contenttype.maxhistory - maximum number of content types to keep
41 | extensions.httprequester.header.maxhistory - maximum number of header names to keep
42 |
43 |
You can add custom methods to the list of available HTTP methods.
44 | To add new Methods: enter "about:config" in your URL bar. Then filter on:
45 | extensions.httprequester.http.methods.custom.write
46 |
47 | Double-click the value to modify it. You can change it to a list of comma-separated values like: ["PROPFIND", "PATCH"]
48 | You can also add read-only custom methods too (these methods will not send any entity body) via extensions.httprequester.http.methods.custom.read
49 |
50 | If you have any questions/comments/suggestions, shoot me a note.
51 |
52 |
--------------------------------------------------------------------------------
/build/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/build/launchFFSavePID.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | value=`cat /Users/tommut/dev/ff-addons/pid.txt`
4 | echo "$value"
5 |
6 | kill -9 $value
7 |
8 | /Applications/Firefox.app/Contents/MacOS/firefox-bin -p reminderfox-dev & echo $! > /Users/tommut/dev/ff-addons/pid.txt
9 |
--------------------------------------------------------------------------------
/src/chrome.manifest:
--------------------------------------------------------------------------------
1 | content httprequester content/
2 | overlay chrome://browser/content/browser.xul chrome://httprequester/content/overlay.xul
3 |
4 | locale httprequester en-US locale/en-US/
5 |
6 | skin httprequester classic/1.0 skin/
7 | style chrome://global/content/customizeToolbar.xul chrome://httprequester/skin/overlay.css
8 |
--------------------------------------------------------------------------------
/src/chrome/icons/default/httprequester-window.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tommut/HttpRequester/d62a6ea6f32406ab44d494458e652c189d2d5fe0/src/chrome/icons/default/httprequester-window.ico
--------------------------------------------------------------------------------
/src/chrome/icons/default/httprequester-window.xpm:
--------------------------------------------------------------------------------
1 | /* XPM */
2 | static char * httprequester_xpm[] = {
3 | "32 32 3 1",
4 | " c None",
5 | ". c #00A900",
6 | "+ c #F20000",
7 | " ",
8 | " ... ",
9 | " ...... ",
10 | " ........ ",
11 | " ....................... ",
12 | " .......................... ",
13 | " .......................... ",
14 | " ....................... ",
15 | " ........ ",
16 | " ...... ",
17 | " .... ",
18 | " ",
19 | " ",
20 | " ",
21 | " ",
22 | " ",
23 | " ",
24 | " ",
25 | " ",
26 | " ",
27 | " + ",
28 | " +++ ",
29 | " +++++ ",
30 | " +++++++ ",
31 | " +++++++++++++++++++++++ ",
32 | " +++++++++++++++++++++++++ ",
33 | " +++++++++++++++++++++++ ",
34 | " +++++++ ",
35 | " +++++ ",
36 | " ++++ ",
37 | " + ",
38 | " "};
39 |
--------------------------------------------------------------------------------
/src/content/Base64.js:
--------------------------------------------------------------------------------
1 | function Base64() {
2 | this._keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
3 | }
4 |
5 | Base64.prototype.encode = function(input) {
6 | var output = "";
7 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
8 | var i = 0;
9 |
10 | //input = this._utf8_encode(input);
11 |
12 | while (i < input.length) {
13 |
14 | chr1 = input.charCodeAt(i++);
15 | chr2 = input.charCodeAt(i++);
16 | chr3 = input.charCodeAt(i++);
17 |
18 | enc1 = chr1 >> 2;
19 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
20 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
21 | enc4 = chr3 & 63;
22 |
23 | if (isNaN(chr2)) {
24 | enc3 = enc4 = 64;
25 | } else if (isNaN(chr3)) {
26 | enc4 = 64;
27 | }
28 |
29 | output = output +
30 | this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
31 | this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
32 |
33 | }
34 |
35 | return output;
36 | }
37 |
38 | Base64.prototype.decode = function(input) {
39 | var output = "";
40 | var chr1, chr2, chr3;
41 | var enc1, enc2, enc3, enc4;
42 | var i = 0;
43 |
44 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
45 |
46 | while (i < input.length) {
47 |
48 | enc1 = this._keyStr.indexOf(input.charAt(i++));
49 | enc2 = this._keyStr.indexOf(input.charAt(i++));
50 | enc3 = this._keyStr.indexOf(input.charAt(i++));
51 | enc4 = this._keyStr.indexOf(input.charAt(i++));
52 |
53 | chr1 = (enc1 << 2) | (enc2 >> 4);
54 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
55 | chr3 = ((enc3 & 3) << 6) | enc4;
56 |
57 | output = output + String.fromCharCode(chr1);
58 |
59 | if (enc3 != 64) {
60 | output = output + String.fromCharCode(chr2);
61 | }
62 | if (enc4 != 64) {
63 | output = output + String.fromCharCode(chr3);
64 | }
65 |
66 | }
67 |
68 | //output = this._utf8_decode(output);
69 |
70 | return output;
71 | }
72 |
73 | Base64.prototype._utf8_encode = function (string) {
74 | string = string.replace(/\r\n/g,"\n");
75 | var utftext = "";
76 |
77 | for (var n = 0; n < string.length; n++) {
78 |
79 | var c = string.charCodeAt(n);
80 |
81 | if (c < 128) {
82 | utftext += String.fromCharCode(c);
83 | }
84 | else if((c > 127) && (c < 2048)) {
85 | utftext += String.fromCharCode((c >> 6) | 192);
86 | utftext += String.fromCharCode((c & 63) | 128);
87 | }
88 | else {
89 | utftext += String.fromCharCode((c >> 12) | 224);
90 | utftext += String.fromCharCode(((c >> 6) & 63) | 128);
91 | utftext += String.fromCharCode((c & 63) | 128);
92 | }
93 |
94 | }
95 |
96 | return utftext;
97 | }
98 |
99 | // private method for UTF-8 decoding
100 | Base64.prototype._utf8_decode = function (utftext) {
101 | var string = "";
102 | var i = 0;
103 | var c = c1 = c2 = 0;
104 |
105 | while ( i < utftext.length ) {
106 |
107 | c = utftext.charCodeAt(i);
108 |
109 | if (c < 128) {
110 | string += String.fromCharCode(c);
111 | i++;
112 | }
113 | else if((c > 191) && (c < 224)) {
114 | c2 = utftext.charCodeAt(i+1);
115 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
116 | i += 2;
117 | }
118 | else {
119 | c2 = utftext.charCodeAt(i+1);
120 | c3 = utftext.charCodeAt(i+2);
121 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
122 | i += 3;
123 | }
124 |
125 | }
126 |
127 | return string;
128 | }
129 |
--------------------------------------------------------------------------------
/src/content/GoogleLogin.js:
--------------------------------------------------------------------------------
1 | var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
2 | var GoogleLogin = {
3 | data: null,
4 | init: function(data) {
5 | this.data = data;
6 | document.getElementById('username').value = data.username;
7 | document.getElementById('password').value = data.password;
8 | document.getElementById('service').value = data.service;
9 | },
10 | authenticate: function() {
11 | //document.getElementById('failure').value = "";
12 | var current = this;
13 | var service = document.getElementById('service').value;
14 | if (!service || service.length==0) {
15 | this.showError("The service is missing (e.g. blogger).");
16 | return;
17 | }
18 | var username = document.getElementById('username').value;
19 | if (!username || username.length==0) {
20 | this.showError("The username is missing.");
21 | return;
22 | }
23 | var password = document.getElementById('password').value;
24 | if (!password) {
25 | password = "";
26 | }
27 | var loginBody = "service="+service+"&Email="+username+"&Passwd="+password;
28 | HTTP("POST","https://www.google.com/accounts/ClientLogin",{
29 | timeout: 30*1000,
30 | contentType: "application/x-www-form-urlencoded",
31 | onSuccess: function(status,doc,text) {
32 | var regex = /Auth=.+/;
33 | var match = regex.exec(text);
34 | var auth=match[0].substring(5);
35 | current.onSuccess(auth);
36 | },
37 | onFailure: function(status,doc,text) {
38 | current.data.success = false;
39 | if (text.length>30) {
40 | text = text.substring(0,30)+"...";
41 | }
42 | current.showError("Authnetication failed: ("+status+") "+text);
43 | },
44 | body: loginBody
45 | });
46 | },
47 | showError: function(msg) {
48 | document.getElementById('failure').value = msg;
49 | },
50 | onSuccess: function(auth) {
51 | this.data.auth = auth;
52 | this.data.success = true;
53 | this.data.username = document.getElementById('username').value;
54 | this.data.password = document.getElementById('password').value;
55 | this.data.service = document.getElementById('service').value;
56 | setTimeout(function(){ window.close(); },200);
57 | },
58 | cancel: function() {
59 | this.data.success = false;
60 | this.data.username = document.getElementById('username').value;
61 | this.data.password = document.getElementById('password').value;
62 | this.data.service = document.getElementById('service').value;
63 | window.close();
64 | }
65 |
66 |
67 |
68 | }
--------------------------------------------------------------------------------
/src/content/HTTP.js:
--------------------------------------------------------------------------------
1 | var _HTTP_HEADER_NAME = new RegExp("^([a-zA-Z0-9_-]+):");
2 |
3 | function _HTTP_parseHeaders(headerText)
4 | {
5 | var headers = {};
6 | if (headerText) {
7 | var eol = headerText.indexOf("\n");
8 | while (eol>=0) {
9 | var line = headerText.substring(0,eol);
10 | headerText = headerText.substring(eol+1);
11 | while (headerText.length>0 && !headerText.match(_HTTP_HEADER_NAME)) {
12 | eol = headerText.indexOf("\n");
13 | var nextLine = eol<0 ? headerText : headerText.substring(0,eol);
14 | line = line+' '+nextLine;
15 | headerText = eol<0 ? "" : headerText.substring(eol+1);
16 | }
17 | // Parse the name value pair
18 | var colon = line.indexOf(':');
19 | var name = line.substring(0,colon);
20 | var value = line.substring(colon+1);
21 | headers[name] = value;
22 | eol = headerText.indexOf("\n");
23 | }
24 | if (headerText.length>0) {
25 | var colon = headerText.indexOf(':');
26 | var name = headerText.substring(0,colon);
27 | var value = headerText.substring(colon+1);
28 | headers[name] = value;
29 | }
30 | }
31 | return headers;
32 | }
33 |
34 | /**
35 | * The following keys can be sent:
36 | * onSuccess (required) a function called when the response is 2xx
37 | * onFailure a function called when the response is not 2xx
38 | * username The username for basic auth
39 | * password The password for basic auth
40 | * overrideMimeType The mime type to use for non-XML response mime types
41 | * timeout A timeout value in milliseconds for the response
42 | * onTimeout A function to call if the request times out.
43 | * body A string containing the entity body of the request
44 | * contentType The content type of the entity body of the request
45 | * headers A hash of optional headers
46 | */
47 | function HTTP(method,url,options)
48 | {
49 | var requester = new XMLHttpRequest();
50 | var timeout = null;
51 | if (!options.synchronizedRequest) {
52 |
53 | requester.onreadystatechange = function() {
54 | switch (requester.readyState) {
55 | case 0:
56 | if (options.onUnsent) {
57 | options.onUnsent(requester);
58 | }
59 | break;
60 | case 1:
61 | if (options.onOpened) {
62 | options.onOpened(requester);
63 | }
64 | break;
65 | case 2:
66 | if (options.onHeaders) {
67 | options.onHeaders(requester);
68 | }
69 | break;
70 | case 3:
71 | if (options.onLoading) {
72 | options.onLoading(requester);
73 | }
74 | break;
75 | case 4:
76 | if (timeout) {
77 | clearTimeout(timeout);
78 | }
79 | if (requester.status==0 || (requester.status>=200 && requester.status<300)) {
80 | options.onSuccess(
81 | requester.status,
82 | requester.responseXML,
83 | requester.responseText,
84 | options.returnHeaders ? _HTTP_parseHeaders(requester.getAllResponseHeaders()) : null,
85 | requester.statusText,
86 | options.id
87 | );
88 | } else {
89 | if (options.onFailure) {
90 | options.onFailure(
91 | requester.status,
92 | requester.responseXML,
93 | requester.responseText,
94 | options.returnHeaders ? _HTTP_parseHeaders(requester.getAllResponseHeaders()) : null,
95 | requester.statusText,
96 | options.id
97 | );
98 | }
99 | }
100 | break;
101 | }
102 | }
103 | }
104 |
105 | if (options.overrideMimeType) {
106 | requester.overrideMimeType(options.overrideMimeType);
107 | }
108 |
109 | // username/password can not accurately be set on XMLHttpRequest parameter, as it is not
110 | // fully supported; instead the Authorization header is added previously
111 | options.username = null;
112 | options.password = null;
113 | // for (var key in options.headers) {
114 | // alert("key: " + key + " = " + options.headers[key])
115 | // }
116 |
117 |
118 | if (options.username) {
119 | requester.open(method,url,!options.synchronizedRequest,options.username,options.password);
120 | } else {
121 | requester.open(method,url,!options.synchronizedRequest);
122 | }
123 | if (options.timeout && !options.synchronizedRequest) {
124 | timeout = setTimeout(
125 | function() {
126 | var callback = options.onTimeout ? options.onTimeout : options.onFailure;
127 | callback(0,"Operation timeout.");
128 | },
129 | options.timeout
130 | );
131 | }
132 | if (options.headers) {
133 | for (var name in options.headers) {
134 | requester.setRequestHeader(name,options.headers[name]);
135 | }
136 | }
137 | if (options.body || (options.contentType != null && options.contentType.length > 0)) {
138 | requester.setRequestHeader("Content-Type",options.contentType);
139 | }
140 | if (options.body) {
141 | requester.send(options.body);
142 | } else {
143 | requester.send(null);
144 | }
145 | if (options.synchronizedRequest) {
146 | if (requester.status==0 || (requester.status>=200 && requester.status<300)) {
147 |
148 | options.onSuccess(
149 | requester.status,
150 | requester.responseXML,
151 | requester.responseText,
152 | options.returnHeaders ? _HTTP_parseHeaders(requester.getAllResponseHeaders()) : null,
153 | requester.statusText,
154 | options.id
155 | );
156 | } else {
157 | if (options.onFailure) {
158 | options.onFailure(
159 | requester.status,
160 | requester.responseXML,
161 | requester.responseText,
162 | options.returnHeaders ? _HTTP_parseHeaders(requester.getAllResponseHeaders()) : null,
163 | requester.statusText,
164 | options.id
165 | );
166 | }
167 | }
168 | return {
169 | abort: function() {
170 | }
171 | };
172 | } else {
173 | return {
174 | abort: function() {
175 | clearTimeout(timeout);
176 | requester.abort();
177 | }
178 | };
179 | }
180 | }
181 |
182 |
183 |
--------------------------------------------------------------------------------
/src/content/Response.js:
--------------------------------------------------------------------------------
1 | var Response = {
2 | init: function(data) {
3 |
4 | // create a new response object
5 |
6 | // add it to the Transactions array
7 |
8 | // update the transactions list with last entry (and remove oldest entry)
9 |
10 | // select latest entry in the list; should populate request/response sections based on that.
11 | var titleE = document.getElementById("title");
12 | while (titleE.hasChildNodes()) {
13 | titleE.removeChild(titleE.firstChild);
14 | }
15 |
16 | titleE.appendChild(document.createTextNode(data.title));
17 | this.setResponseStatus(data.status+" "+data.statusText);
18 | this.setResponseContent(data.content, data.responseHeaders['Content-Type'], data.url);
19 |
20 | var grid = document.getElementById("headers");
21 | while (grid.hasChildNodes()) {
22 | grid.removeChild(grid.firstChild);
23 | }
24 | for (var name in data.responseHeaders) {
25 | this.addResponseHeader(name,data.responseHeaders[name]);
26 | }
27 | },
28 | setResponseStatus: function(status) {
29 | document.getElementById("code").value =status ? status : "";
30 | },
31 |
32 | formatXmlFast : function(xml) {
33 | var formatted = '';
34 | var reg = /(>)(<)(\/*)/g;
35 | xml = xml.toString().replace(reg, '$1\r\n$2$3');
36 | var pad = 0;
37 | var nodes = xml.split('\r\n');
38 | for(var n in nodes) {
39 | var node = nodes[n];
40 | var indent = 0;
41 | if (node.match(/.+<\/\w[^>]*>$/)) {
42 | indent = 0;
43 | } else if (node.match(/^<\/\w/)) {
44 | if (pad !== 0) {
45 | pad -= 1;
46 | }
47 | } else if (node.match(/^<\w[^>]*[^\/]>.*$/)) {
48 | indent = 1;
49 | } else {
50 | indent = 0;
51 | }
52 | var padding = '';
53 | for (var i = 0; i < pad; i++) {
54 | padding += ' '; // use 4 spaces for tab padding
55 | }
56 | formatted += padding + node + '\r\n';
57 | pad += indent;
58 | }
59 | return formatted;
60 | //return formatted.replace(/&/g,'&').replace(//g,'>').replace(/ /g, ' ');
61 | },
62 |
63 | formatXml : function (xml) {
64 | var reg = /(>)(<)(\/*)/g;
65 | var wsexp = / *(.*) +\n/g;
66 | var contexp = /(<.+>)(.+\n)/g;
67 | xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
68 | var pad = 0;
69 | var formatted = '';
70 | var lines = xml.split('\n');
71 | var indent = 0;
72 | var lastType = 'other';
73 | // 4 types of tags - single, closing, opening, other (text, doctype, comment) - 4*4 = 16 transitions
74 | var transitions = {
75 | 'single->single': 0,
76 | 'single->closing': -1,
77 | 'single->opening': 0,
78 | 'single->other': 0,
79 | 'closing->single': 0,
80 | 'closing->closing': -1,
81 | 'closing->opening': 0,
82 | 'closing->other': 0,
83 | 'opening->single': 1,
84 | 'opening->closing': 0,
85 | 'opening->opening': 1,
86 | 'opening->other': 1,
87 | 'other->single': 0,
88 | 'other->closing': -1,
89 | 'other->opening': 0,
90 | 'other->other': 0
91 | };
92 |
93 | for (var i = 0; i < lines.length; i++) {
94 | var ln = lines[i];
95 | // ignore first line if it is a standalone directive
96 | if ( i == 0 && ln.indexOf( "/)); // is this line a single tag? ex.
102 | var closing = Boolean(ln.match(/<\/.+>/)); // is this a closing tag? ex.
103 | var opening = Boolean(ln.match(/<[^!].*>/)); // is this even a tag (that's not )
104 | var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other';
105 | var fromTo = lastType + '->' + type;
106 | lastType = type;
107 | var padding = '';
108 |
109 | indent += transitions[fromTo];
110 | for (var j = 0; j < indent; j++) {
111 | padding += '\t';
112 | }
113 | if (fromTo == 'opening->closing')
114 | formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'; // substr removes line break (\n) from prev loop
115 | else
116 | formatted += padding + ln + '\n';
117 | }
118 |
119 | return formatted;
120 | },
121 |
122 | getFileExtensionFromRequestUri: function (requestUrl) {
123 | var fileExtension = null;
124 | var checkFileExtension = App.getPreferenceBool("checkFileExtensionForRenderType");
125 | if (checkFileExtension && requestUrl != null) {
126 | var index = requestUrl.lastIndexOf("/");
127 | if (index > -1) {
128 | var lastRequestSegment = requesturl.substring(index);
129 | index = lastRequestSegment.lastIndexOf(".");
130 | if (index > -1 && index < lastRequestSegment.length - 1) {
131 | fileExtension = lastRequestSegment.substring(index + 1);
132 | }
133 | }
134 | }
135 | },
136 | getFileExtensionFromContentType: function (contentType) {
137 | // determine file extension from content type
138 | var fileExtension = null;
139 | //alert( "Content type: " + contentType )
140 | if (contentType && contentType.search('json') > -1) {
141 | fileExtension = "json";
142 | }
143 | else if (contentType && contentType.search('xml') > -1) {
144 | fileExtension = "xml";
145 | }
146 | else if (contentType && contentType.search('html') > -1) {
147 | fileExtension = "html";
148 | }
149 | else {
150 | fileExtension = "txt";
151 | }
152 | //alert( "RETURNING THIS: " + fileExtension );
153 | return fileExtension;
154 | },
155 |
156 | saveResponseToFile: function (fileExtension, formattedContent) {
157 | // write out to file
158 | var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
159 |
160 | var xFile = Components.classes["@mozilla.org/file/directory_service;1"]
161 | .getService(Components.interfaces.nsIProperties)
162 | .get("ProfD", Components.interfaces.nsIFile);
163 | xFile.append("httpRequester");
164 | xFile.append("httprequester.response." + fileExtension);
165 | var defaultFilePath = xFile.path;
166 | file.initWithPath(defaultFilePath);
167 | if (file.exists() === false) {
168 | file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420);
169 | }
170 | this.writeStringToFile(formattedContent, file);
171 |
172 | return defaultFilePath;
173 | },
174 |
175 | log : function( msg ) {
176 | var cs1 = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
177 | cs1.logStringMessage("httprequester: " + msg);
178 | console.error(msg)
179 | },
180 |
181 |
182 | setResponseContent: function(content, contentType, requestUrl) {
183 | var renderWithBrowser = App.getPreferenceBool("renderResponseBrowser");
184 | if ( renderWithBrowser ) {
185 | // if pref is set to checkFileExtension (user may want to turn this off if requests end
186 | // in .something and want to use the content type always instead), then look for a file
187 | // extension. If there is one, just write the file out to that.
188 | var fileExtension = this.getFileExtensionFromRequestUri(requestUrl);
189 | if ( fileExtension == null ) {
190 | fileExtension = this.getFileExtensionFromContentType(contentType);
191 | }
192 |
193 | // if there's no actual content, default to txt
194 | if ( content == null || content.length == 0 ) {
195 | fileExtension = "txt";
196 | }
197 |
198 | var filePath = this.saveResponseToFile(fileExtension, content);
199 |
200 | // need to first change the url (we user a dummy url); otherwise, if navigating
201 | // between two XML or HTML files, the URL would be the same and changing it would
202 | // do nothing
203 | document.getElementById("browserIframe").setAttribute("src","file://tmp" );
204 | document.getElementById("browserIframe").setAttribute("src","file://" + filePath);
205 |
206 | // we do the process again, as it seems on Windows when just setting the src the first
207 | // time it would sometimes renders as text (all the text from all xml elements) and not
208 | // as XML. Clearing the src and resetting it a second time seems to always work.
209 | document.getElementById("browserIframe").setAttribute("src","file://tmp" );
210 | document.getElementById("browserIframe").setAttribute("src","file://" + filePath);
211 | // this.log("request: " + requestUrl + "\nIframe: " + document.getElementById("browserIframe").getAttribute("src") + " \nfilepath: " + filePath);
212 | }
213 | else {
214 | // output as Text
215 | formattedContent = content;
216 | if (formattedContent != null && formattedContent.length > 0) {
217 | var prettyPrint = App.getPreferenceBool("prettyPrintResponse");
218 | if (prettyPrint) {
219 | // if pretty print is on, format the response before displaying in
220 | // response content field
221 | if (contentType && contentType.search(/.*\/.*json/i) > -1) {
222 | formattedContent = JSON.stringify(JSON.parse(content), null, 4);
223 | }
224 | else if (contentType && contentType.search(/.*\/.*xml/i) > -1) {
225 | // the formatXml method does a better job but does not perform as well as formatXmlFast
226 | var fastPrettyPrint = App.getPreferenceBool("useFastXMLPrettyPrint");
227 | if ( fastPrettyPrint ) {
228 | formattedContent = this.formatXmlFast(content);
229 | }
230 | else {
231 | formattedContent = this.formatXml(content);
232 | }
233 | }
234 | // not currently pretty formatting HTML. Not sure if it makes sense to do so.
235 | // else if (contentType && contentType.search('text/html') > -1) {
236 | // // the formatXml method does a better job but does not perform as well
237 | // //formattedContent = this.formatXml(content);
238 | // formattedContent = this.formatXmlFast(content);
239 | // }
240 | }
241 | }
242 |
243 | // update the response content text field
244 | document.getElementById("response-content").value = formattedContent ? formattedContent : "";
245 | }
246 | },
247 |
248 | writeStringToFile : function(outputStr, file){
249 | var outputStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
250 | .createInstance(Components.interfaces.nsIFileOutputStream);
251 | outputStream.init(file, 0x04 | 0x08 | 0x20, 420, 0);
252 |
253 | var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
254 | .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
255 | converter.charset = "UTF-8";
256 |
257 | var chunk = null;
258 | try {
259 | chunk = converter.ConvertFromUnicode(outputStr);
260 | }
261 | catch (e) {
262 | chunk = outputStr;
263 | }
264 | outputStream.write(chunk, chunk.length);
265 |
266 | var fin = converter.Finish();
267 | if (fin.length > 0)
268 | outputStream.write(fin, fin.length);
269 | outputStream.close();
270 |
271 | },
272 |
273 | addResponseHeader: function(name,value) {
274 | var grid = document.getElementById("headers");
275 | var row = grid.ownerDocument.createElement("row");
276 | grid.appendChild(row);
277 | var nameLabel = row.ownerDocument.createElement("label");
278 | nameLabel.setAttribute("value",name);
279 | row.appendChild(nameLabel);
280 | var valueLabel = row.ownerDocument.createElement("textbox");
281 | valueLabel.setAttribute("value",value);
282 | row.appendChild(valueLabel);
283 | },
284 | clearResponseview: function() {
285 | var titleE = document.getElementById("title");
286 | while (titleE.hasChildNodes()) {
287 | titleE.removeChild(titleE.firstChild);
288 | }
289 | this.setResponseStatus(null);
290 | this.setResponseContent(null);
291 |
292 | var grid = document.getElementById("headers");
293 | while (grid.hasChildNodes()) {
294 | grid.removeChild(grid.firstChild);
295 | }
296 | }
297 |
298 | }
--------------------------------------------------------------------------------
/src/content/about.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 | HttpRequester
8 |
9 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
--------------------------------------------------------------------------------
/src/content/httprequester.js:
--------------------------------------------------------------------------------
1 | var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
2 |
3 | var mimeService = Components.classes["@mozilla.org/mime;1"].getService(Components.interfaces.nsIMIMEService);
4 |
5 | var App = {
6 | initialized: false,
7 | inprogress: null,
8 | synopsis: null,
9 | elements: {},
10 | transactions: new Array(),
11 | lastService: null,
12 | urlHistory: {},
13 | contentTypeHistory: {},
14 | headerNameHistory: {},
15 | customReadHttpMethods: {},
16 | customWriteHttpMethdods: {},
17 |
18 | Transaction: function () {
19 | this.timeStamp = null;
20 | this.requestTransaction = null;
21 | this.responseTransaction = null;
22 | },
23 |
24 | RequestTransaction: function () {
25 | this.httpMethod = null;
26 | this.url = null;
27 | this.requestHeaders = {},
28 | this.contentType = null;
29 | this.content = null;
30 | this.parameters = {}
31 | this.filename = null;
32 | this.username = null;
33 | this.password = null;
34 | this.timeout = null;
35 | this.base64 = null;
36 | },
37 | ResponseTransaction: function () {
38 | this.title = null;
39 | this.status = null;
40 | this.statusText = null;
41 | this.content = null;
42 | this.responseHeaders = null;
43 | this.responseTimeStamp = null;
44 | },
45 |
46 | getPreferenceString: function (name) {
47 | var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.httprequester.");
48 | if (preferencesService) {
49 | try {
50 | return preferencesService.getCharPref(name);
51 | } catch (ex) {
52 | // no preference
53 | }
54 | }
55 | return null;
56 | },
57 | getPreferenceComplex: function (name) {
58 | var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.httprequester.");
59 | if (preferencesService) {
60 | try {
61 | return preferencesService.getComplexValue(name, Components.interfaces.nsISupportsString).data;
62 | } catch (ex) {
63 | // no preference
64 | }
65 | }
66 | return null;
67 | },
68 | setPreferenceComplex: function (name, value) {
69 | var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].
70 | getService(Components.interfaces.nsIPrefService).getBranch("extensions.httprequester.");
71 | if (preferencesService) {
72 | try {
73 | var sString = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
74 | sString.data = value;
75 | preferencesService.setComplexValue(name, Components.interfaces.nsISupportsString, sString);
76 | } catch (ex) {
77 | // no preference
78 | }
79 | }
80 | },
81 | getPreferenceInt: function (name) {
82 | var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.httprequester.");
83 | if (preferencesService) {
84 | try {
85 | return preferencesService.getIntPref(name);
86 | } catch (ex) {
87 | // no preference
88 | }
89 | }
90 | return null;
91 | },
92 | getPreferenceBool: function (name) {
93 | var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.httprequester.");
94 | if (preferencesService) {
95 | try {
96 | return preferencesService.getBoolPref(name);
97 | } catch (ex) {
98 | // no preference
99 | }
100 | }
101 | return null;
102 | },
103 |
104 | setPreferenceString: function (name, value) {
105 | var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.httprequester.");
106 | if (preferencesService) {
107 | preferencesService.setCharPref(name, value);
108 | }
109 | },
110 | setPreferenceBool: function (name, value) {
111 | var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.httprequester.");
112 | if (preferencesService) {
113 | preferencesService.setBoolPref(name, value);
114 | }
115 | },
116 | getMaxHistory: function () {
117 | var max = this.getPreferenceInt("maxhistory")
118 | if (max == null) {
119 | max = 25;
120 | }
121 | return max;
122 | },
123 |
124 | getMaxUrlHistory: function () {
125 | var max = this.getPreferenceInt("url.maxhistory")
126 | if (max == null) {
127 | max = 10;
128 | }
129 | return max;
130 | },
131 | getMaxContentTypeHistory: function () {
132 | var max = this.getPreferenceInt("contenttype.maxhistory")
133 | if (max == null) {
134 | max = 10;
135 | }
136 | return max;
137 | },
138 | getMaxHeaderHistory: function () {
139 | var max = this.getPreferenceInt("header.maxhistory")
140 | if (max == null) {
141 | max = 10;
142 | }
143 | return max;
144 | },
145 | findInTextBox: function () {
146 | // if the response-content is focused, we will perform a Find for the response content
147 | if (document.getElementById("response-content").getAttribute("focused")) {
148 | var nsIPromptService = Components.interfaces.nsIPromptService;
149 | var nsPrompt_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1";
150 | var gPromptService = Components.classes[nsPrompt_CONTRACTID].getService(nsIPromptService);
151 | var result = { value: this.lastSearchString };
152 | var dummy = { value: 0 };
153 |
154 | if (gPromptService.prompt(window,
155 | "Find text in response",
156 | "Enter text to search for:",
157 | result,
158 | null,
159 | dummy)) {
160 | this.lastSearchString = result.value;
161 |
162 | this.doFindNext();
163 | }
164 | }
165 | },
166 | doFindNext: function () {
167 | // if the response-content is focused, we will perform a Find for the response content
168 | if (document.getElementById("response-content").getAttribute("focused")) {
169 | var text = document.getElementById("response-content").value;
170 |
171 | var start = document.getElementById("response-content").selectionStart;
172 |
173 | if (start < text.length - 1) {
174 | start = start + 1;
175 | }
176 | var index = text.toUpperCase().indexOf(this.lastSearchString.toUpperCase(), start);
177 | if (index == -1) {
178 | // restart; look from the beginning
179 | index = text.toUpperCase().indexOf(this.lastSearchString.toUpperCase());
180 | }
181 | if (index == -1) {
182 | alert("No match found.");
183 | }
184 | else {
185 | document.getElementById("response-content").select();
186 | document.getElementById("response-content").setSelectionRange(index, (index + this.lastSearchString.length));
187 | }
188 | }
189 |
190 | },
191 | log : function( msg ) {
192 | var cs1 = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
193 | cs1.logStringMessage("httprequester: " + msg);
194 | console.error(msg)
195 | },
196 |
197 | updateParamsFromUri: function() {
198 | // remove params
199 | treeChildren = document.getElementById("paramtreechildren");
200 | if ( treeChildren != null && treeChildren.childNodes.length > 0 ) {
201 | while (treeChildren.hasChildNodes()) {
202 | treeChildren.removeChild(treeChildren.firstChild);
203 | }
204 | }
205 |
206 | var urlstr = this.elements["url"].value;
207 |
208 | var paramStr = null;
209 | try {
210 | //Support after Gecko 26
211 | var url1 = new URL(urlstr);
212 | paramStr = url1.search;
213 | } catch (ex) {
214 | if (urlstr.indexOf("?") != -1) {
215 | var search = urlstr.replace(/^\s+/,'').replace(/\s+$/,'').match(/([^?#]*)(#.*)?$/);
216 | if(search){
217 | paramStr = search[1];
218 | }
219 | }
220 | }
221 | if ( paramStr != null && paramStr.length > 0 ) {
222 | // Convert query string to object
223 | var queries = paramStr.replace(/^\?/, '').split('&');
224 | for( i = 0; i < queries.length; i++ ) {
225 | var split = queries[i].split('=');
226 | var paramName = split[0];
227 | var paramValue= split[1];
228 | // decode value from URL params (we encode when we add the params to the uri)
229 | if ( paramValue ) {
230 | paramValue = decodeURIComponent(paramValue);
231 | }
232 | this.addParameter(paramName, paramValue);
233 | // .request
234 | }
235 | }
236 | },
237 |
238 | init: function () {
239 | this.initialized = true;
240 | // show advanced section if preference is set
241 | if (this.getPreferenceBool("showAdvancedOptions")) {
242 | document.getElementById("advancedSettings1").setAttribute("hidden", false);
243 | document.getElementById("advancedSettings2").setAttribute("hidden", false);
244 | }
245 |
246 | if (this.getPreferenceBool("prettyPrintResponse")) {
247 | var prettyPrintCheckbox = document.getElementById("prettyPrint");
248 | prettyPrintCheckbox.setAttribute("checked", true);
249 | }
250 |
251 | var group = document.getElementById("responseRenderType");
252 | if (this.getPreferenceBool("renderResponseBrowser")) {
253 | group.selectedIndex = 0;
254 | }
255 | else {
256 | group.selectedIndex =1;
257 | }
258 |
259 | // There was a component that handled storing some values; this no longer works
260 | // in Firefox 4, so was removed. The values are instead stored to the preferences.
261 | var httprequesterService = new Object();
262 | httprequesterService.contentType = this.getPreferenceString("contentType");
263 | httprequesterService.contentType = "application/json";
264 | httprequesterService.url = this.getPreferenceString("url");
265 | httprequesterService.file = "";
266 |
267 | this.elements["filename"] = document.getElementById("filename");
268 | this.elements["contentType"] = document.getElementById("ctype");
269 | this.elements["username"] = document.getElementById("username");
270 | this.elements["password"] = document.getElementById("password");
271 | this.elements["content"] = document.getElementById("content");
272 | this.elements["url"] = document.getElementById("url");
273 | this.elements["timeout"] = document.getElementById("timeout");
274 |
275 | this.elements["filename"].value = httprequesterService.file;
276 | this.elements["contentType"].value = httprequesterService.contentType;
277 | this.elements["url"].value = httprequesterService.url;
278 | if (httprequesterService.username) {
279 | this.elements["username"].value = httprequesterService.username;
280 | }
281 | if (httprequesterService.password) {
282 | this.elements["password"].value = httprequesterService.password;
283 | }
284 | var current = this;
285 | document.getElementById("base64-encode").onclick = function () {
286 | var value = current.elements["content"].value;
287 | if (value.length > 0) {
288 | var encoder = new Base64();
289 | current.elements["content"].value = encoder.encode(value);
290 | }
291 | }
292 |
293 | document.getElementById("header-list").onkeypress = function (event) {
294 | // don't listen for delete key, as it interferes with pressing delete on the editable field
295 | // if (event.keyCode == 8 || event.keyCode == 46) {
296 | // current.onDeleteHeader();
297 | // }
298 | };
299 |
300 | document.getElementById("url").onblur = function (event) {
301 | App.updateParamsFromUri();
302 | };
303 |
304 | document.getElementById("parameter-list").onkeypress = function (event) {
305 | // don't listen for delete key, as it interferes with pressing delete on the editable field
306 | // if (event.keyCode == 8 || event.keyCode == 46) {
307 | // current.onDeleteParameter();
308 | // }
309 | if (event.keyCode == 13 ) { // if return key is pressed, means param was edited. Update URL
310 | this.updateUrlWithParams();
311 | }
312 | };
313 |
314 | // listen for editable changes in the parameter list so we can update the URL
315 | document.getElementById("parameter-list").onblur = function (event) {
316 | App.updateUrlWithParams();
317 | };
318 |
319 | document.getElementById("transaction-list").onkeypress = function (event) {
320 | if (event.keyCode == 8 || event.keyCode == 46) {
321 | current.onDeleteTransaction();
322 | }
323 | };
324 | document.getElementById("transaction-list").ondblclick = function (event) {
325 | current.viewRawRequest();
326 | };
327 |
328 |
329 | // load history
330 | var history = this.getPreferenceComplex("history");
331 | if (history != null && history.length > 0) {
332 | this.transactions = JSON.parse(history);
333 |
334 | for (var i = this.transactions.length - 1; i >= 0; i--) {
335 | this.addTransactionToList(this.transactions[i]);
336 | }
337 | }
338 |
339 | // load urls
340 | var urlHistory = this.getPreferenceComplex("url.history");
341 | if (urlHistory != null && urlHistory.length > 0) {
342 | this.urlHistory = JSON.parse(urlHistory);
343 | }
344 | else {
345 | this.urlHistory = new Array();
346 | }
347 | this.updateMenuList("url", this.urlHistory);
348 |
349 | // load content type history
350 | var contentTypeHistory = this.getPreferenceComplex("contentType.history");
351 | if (contentTypeHistory != null && contentTypeHistory.length > 0) {
352 | this.contentTypeHistory = JSON.parse(contentTypeHistory);
353 | }
354 | else {
355 | this.contentTypeHistory = new Array();
356 | }
357 | this.updateMenuList("ctype", this.contentTypeHistory);
358 |
359 | // load headers
360 | var headerHistory = this.getPreferenceComplex("header.history");
361 | if (headerHistory != null && headerHistory.length > 0) {
362 | this.headerNameHistory = JSON.parse(headerHistory);
363 | }
364 | else {
365 | this.headerNameHistory = new Array();
366 | }
367 | this.updateMenuList("header-name", this.headerNameHistory);
368 |
369 | // set appropriate content UI controls based on radio button
370 | this.contentBodyRadioButtonChanged();
371 |
372 | // load custom methods
373 | var sendCommands = this.getPreferenceString("http.methods.custom.write");
374 | if (sendCommands != null && sendCommands.length > 0) {
375 | this.customWriteHttpMethods = JSON.parse(sendCommands);
376 | }
377 | else {
378 | this.customWriteHttpMethods = new Array();
379 | }
380 | var readCommands = this.getPreferenceString("http.methods.custom.read");
381 | if (readCommands != null && readCommands.length > 0) {
382 | this.customReadHttpMethods = JSON.parse(readCommands);
383 | }
384 | else {
385 | this.customReadHttpMethods = new Array();
386 | }
387 |
388 | // populate METHOD dropdown with custom methods
389 | var methodList = document.getElementById("method");
390 | for (var i = 0; i < this.customWriteHttpMethods.length; i++) {
391 | var newMethod = document.createElement("menuitem");
392 | newMethod.setAttribute("label", this.customWriteHttpMethods[i]);
393 | newMethod.setAttribute("value", this.customWriteHttpMethods[i]);
394 | methodList.firstChild.appendChild(newMethod);
395 | }
396 | for (var i = 0; i < this.customReadHttpMethods.length; i++) {
397 | var newMethod = document.createElement("menuitem");
398 | newMethod.setAttribute("label", this.customReadHttpMethods[i]);
399 | newMethod.setAttribute("value", this.customReadHttpMethods[i]);
400 | methodList.firstChild.appendChild(newMethod);
401 | }
402 | },
403 | saveSettings: function () {
404 | var historyString = JSON.stringify(this.transactions);
405 | this.setPreferenceComplex("history", historyString);
406 |
407 | var urlhistoryString = JSON.stringify(this.urlHistory);
408 | this.setPreferenceComplex("url.history", urlhistoryString);
409 |
410 | var contentTypehistoryString = JSON.stringify(this.contentTypeHistory);
411 | this.setPreferenceComplex("contentType.history", contentTypehistoryString);
412 |
413 | var headerHistoryString = JSON.stringify(this.headerNameHistory);
414 | this.setPreferenceComplex("header.history", headerHistoryString);
415 | },
416 |
417 | saveValues: function () {
418 |
419 |
420 | this.setPreferenceString("file", this.elements["filename"].value);
421 | this.setPreferenceString("contentType", this.elements["contentType"].value);
422 | this.setPreferenceString("url", this.elements["url"].value);
423 | this.setPreferenceString("username", this.elements["username"].value);
424 | this.setPreferenceString("password", this.elements["password"].value);
425 | },
426 |
427 | importValues: function () {
428 | this.elements["filename"].value = this.getPreferenceString("file");
429 | this.elements["contentType"].value = this.getPreferenceString("contentType");
430 | this.elements["url"].value = this.getPreferenceString("url");
431 | this.elements["username"].value = this.getPreferenceString("username");
432 | this.elements["password"].value = this.getPreferenceString("password");
433 | },
434 |
435 | savePreferences: function () {
436 | this.setPreferenceString("contentType", this.elements["contentType"].value);
437 | this.setPreferenceString("url", this.elements["url"].value);
438 | },
439 |
440 | /*
441 | * Open a "browse for folder" dialog to locate an extension directory
442 | * Add the the selected directory to the dropdown list and set it as
443 | * the current working directory.
444 | */
445 | browseForFile: function () {
446 | var nsIFilePicker = Components.interfaces.nsIFilePicker;
447 | var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
448 | fp.init(window, "Choose File to Upload", nsIFilePicker.modeOpen);
449 | if (fp.show() == nsIFilePicker.returnOK) {
450 | var filenm = this.elements["filename"];
451 | var item = filenm.value = fp.file.path;
452 | //httprequesterService.file = fp.file.path;
453 | try {
454 | this.elements["contentType"].value = mimeService.getTypeFromFile(fp.file);
455 | } catch (ex) {
456 | this.elements["contentType"].value = "application/binary";
457 | }
458 | }
459 | },
460 | showGoogleLogin: function () {
461 | var currentApp = this;
462 | var data = {
463 | username: this.elements["username"].value,
464 | password: this.elements["password"].value,
465 | service: currentApp.lastService,
466 | auth: null
467 | };
468 | window.openDialog(
469 | 'chrome://httprequester/content/google-login.xul', 'google-login', 'modal,centerscreen,chrome,resizable',
470 | data
471 | );
472 | if (data.success) {
473 | this.googleAuth = data.auth;
474 | //this.requestHeaders["authorization"] = "GoogleLogin auth="+this.googleAuth;
475 | this.addRequestHeader(authorization, "GoogleLogin auth=" + this.googleAuth);
476 | document.getElementById('google-login').setAttribute("label", "Google Auth'd");
477 | }
478 | this.servive = data.service;
479 | },
480 |
481 |
482 | doMethodRequest: function () {
483 | var method = document.getElementById("method").value;
484 | if (method == "GET") {
485 | this.getURL();
486 | } else if (method == "POST") {
487 | this.postURL();
488 | } else if (method == "PUT") {
489 | this.putURL();
490 | } else if (method == "DELETE") {
491 | this.deleteURL();
492 | } else if (method == "HEAD") {
493 | this.headURL();
494 | } else if (method == "OPTIONS") {
495 | this.optionsURL();
496 | } else if (method == "PATCH") {
497 | this.sendCustomCommand(method)
498 | }
499 | else {
500 | // custom methods
501 | for (var i = 0; i < this.customWriteHttpMethods.length; i++) {
502 | if (method == this.customWriteHttpMethods[i]) {
503 | this.sendCustomCommand(method)
504 | break;
505 | }
506 | }
507 | for (var i = 0; i < this.customReadHttpMethods.length; i++) {
508 | if (method == this.customReadHttpMethods[i]) {
509 | this.getCustomCommand(method)
510 | break;
511 | }
512 | }
513 | }
514 | },
515 |
516 | postURL: function () {
517 | this.handleSend("POST");
518 | },
519 |
520 | putURL: function () {
521 | this.handleSend("PUT");
522 | },
523 |
524 | getURL: function () {
525 | this.handleGet("GET");
526 | },
527 | getURLHotKey: function (event) {
528 | if (event.keyCode == 13) { // if return key is pressed in URL field, do a GET
529 | this.handleGet("GET");
530 | }
531 | },
532 | refreshUrlList: function() {
533 | var urlstr = this.elements["url"].value;
534 | document.getElementById("tooltiptextval").setAttribute("value", urlstr);
535 |
536 | App.updateParamsFromUri();
537 | },
538 | deleteURL: function () {
539 | this.handleGet("DELETE");
540 | },
541 |
542 | headURL: function () {
543 | this.handleGet("HEAD");
544 | },
545 |
546 | optionsURL: function () {
547 | this.handleGet("OPTIONS");
548 | },
549 | sendCustomCommand: function (method) {
550 | this.handleSend(method);
551 | },
552 | getCustomCommand: function (method) {
553 | this.handleGet(method);
554 | },
555 |
556 |
557 |
558 | updateUrlWithParams: function() {
559 | // trim parameters from URI to add them
560 | var urlstr = this.elements["url"].value;
561 | if ( urlstr == null ) {
562 | urlstr = "";
563 | }
564 | urlstr = urlstr.trim();
565 | var index = urlstr.indexOf("?");
566 | if ( index > -1 ) {
567 | urlstr = urlstr.substr(0, index);
568 | }
569 |
570 | if ( urlstr.lastIndexOf( "/" ) == urlstr.length -1 ) {
571 | urlstr = urlstr.substring(0, urlstr.length-1)
572 | }
573 |
574 | urlstr = this.addParametersToURI(urlstr);
575 |
576 | // now set url
577 | this.elements["url"].value = urlstr;
578 |
579 | // update tooltip in URL dropdown
580 | document.getElementById("tooltiptextval").setAttribute("value", urlstr);
581 | },
582 |
583 | handleSend: function (method) {
584 | var fpath = this.elements["filename"].value;
585 | var content = this.elements["content"].value;
586 | var urlstr = this.elements["url"].value;
587 | var ctype = this.elements["contentType"].value;
588 | if (ctype.length == 0) {
589 | this.elements["contentType"].value = "application/json";
590 | ctype = "application/json";
591 | }
592 |
593 | if (urlstr.length == 0) {
594 | alert("A URL must be specified.");
595 | /*
596 | } else if (fpath.length==0 && content.length==0) {
597 | alert("Either a file or content must be specified.");
598 | */
599 | } else if (fpath.length != 0 && content.length != 0) {
600 | alert("You can't have both a file and content to send.");
601 | } else if (fpath.length != 0) {
602 | // add default protocol if not set
603 | if (urlstr.indexOf("://") == -1) {
604 | urlstr = "http://" + urlstr;
605 | }
606 |
607 | this.synopsis = method + " on " + urlstr;
608 | this.sendFileToURL(urlstr, method, fpath, ctype);
609 | } else {
610 | // add default protocol if not set
611 | if (urlstr.indexOf("://") == -1) {
612 | urlstr = "http://" + urlstr;
613 | }
614 |
615 | this.synopsis = method + " on " + urlstr;
616 | this.sendContentToURL(urlstr, method, content, ctype);
617 | }
618 | },
619 | handleGet: function (method) {
620 | var urlstr = this.elements["url"].value;
621 | if (urlstr.length == 0) {
622 | alert("A URL must be specified.");
623 | } else {
624 | // add default protocol if not set
625 | if (urlstr.indexOf("://") == -1) {
626 | urlstr = "http://" + urlstr;
627 | }
628 |
629 | this.synopsis = method + " on " + urlstr;
630 | this.getContentFromURL(urlstr, method);
631 | }
632 | },
633 |
634 | pathToFile: function (path) {
635 | var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
636 | file.initWithPath(path);
637 | return file;
638 | },
639 |
640 | addParametersToURI: function (urlstr) { //
641 | var needSeparator = false;
642 | var parameters = this.getParametersFromUI();
643 | for (var name in parameters) {
644 | var valArray = parameters[name];
645 | for ( var i = 0; i < valArray.length; i++ ) {
646 | var paramValue = valArray[i];
647 |
648 | if (needSeparator) {
649 | urlstr += "&";
650 | } else {
651 | if (urlstr.indexOf('?') < 0) {
652 | urlstr += "?";
653 | }
654 | else {
655 | urlstr += "&";
656 | }
657 | }
658 | var val = encodeURIComponent(paramValue);
659 | if (val != null && val.length > 0) {
660 | urlstr += name + "=" + val;
661 | }
662 | else {
663 | urlstr += name;
664 | }
665 | needSeparator = true;
666 | }
667 | }
668 | return urlstr;
669 | },
670 |
671 | onResult: function (status, xml, text, headers, statusText, id) {
672 | var responseDateStamp = new Date().getTime();
673 | this.inprogress = null;
674 | if (this.progressDialog) {
675 | this.progressDialog.close();
676 | this.progressDialog = null;
677 | }
678 | var title = this.synopsis;
679 | var response = new this.ResponseTransaction();
680 | response.title = title;
681 | response.status = status;
682 | response.statusText = statusText;
683 | response.content = text;
684 | response.responseHeaders = headers;
685 |
686 | // get transaction for this id to add the response
687 | for (var i = 0; i < this.transactions.length; i++) {
688 | if (this.transactions[i].timeStamp == id) {
689 | // set response time stamp
690 | response.responseTimeStamp = responseDateStamp;
691 |
692 | this.transactions[i].responseTransaction = response;
693 | // now update the list with the response
694 | this.editTransactionInList(this.transactions[i]);
695 |
696 | break;
697 | }
698 | }
699 |
700 | },
701 |
702 | sendFileToURL: function(urlstr,method,fpath,ctype) {
703 | try{
704 | //alert("Sending "+fpath+" to "+urlstr+" as "+ctype+" via "+method);
705 | if (this.inprogress) {
706 | var requestToCancel = this.inprogress;
707 | this.inprogress = null;
708 | requestToCancel.abort();
709 | }
710 | var currentApp = this;
711 | var timeout = parseInt(this.elements["timeout"].value)*1000;
712 | var username = this.elements["username"].value;
713 | var password = this.elements["password"].value;
714 | var file = this.pathToFile(fpath);
715 | var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
716 | .createInstance(Components.interfaces.nsIFileInputStream);
717 | fstream.init(file, 1, 0, 0);
718 |
719 | var bufferedStream = Components.classes["@mozilla.org/network/buffered-input-stream;1"]
720 | .createInstance(Components.interfaces.nsIBufferedInputStream);
721 | bufferedStream.init(fstream, file.fileSize);
722 | var currentOpenFile = fstream;
723 |
724 |
725 |
726 |
727 | // create a Request
728 | var dateStamp = new Date().getTime();
729 | var transaction = new this.Transaction();
730 | transaction.timeStamp = dateStamp;
731 |
732 | var request = new this.RequestTransaction();
733 | request.httpMethod = method;
734 | request.url = urlstr;
735 | request.contentType = ctype;
736 | request.filename = fpath;
737 | request.requestHeaders = this.getRequestHeadersFromUI();
738 | request.timeout = timeout;
739 | request.username = username;
740 | request.password = password;
741 | this.requestAdded( transaction, request );
742 | var headersToSend = this.getHeadersWithAuthorization(username, password, request);
743 |
744 | var req = HTTP(
745 | method,
746 | urlstr,
747 | {
748 | timeout: timeout,
749 | contentType: ctype,
750 | body: bufferedStream,
751 | headers: headersToSend,
752 | username: username,
753 | password: password,
754 | returnHeaders: true,
755 | id : transaction.timeStamp,
756 | onSuccess: function(status,xml,text,headers,statusText, id) {
757 | fstream.close();
758 | currentApp.onResult(status,xml,text,headers,statusText, id);
759 | },
760 | onFailure: function(status,xml,text,headers,statusText, id) {
761 | fstream.close();
762 | currentApp.onResult(status,xml,text,headers,statusText, id);
763 | }
764 | }
765 | );
766 | this.inprogress = {
767 | abort: function() {
768 | req.abort();
769 | fstream.close();
770 | }
771 | }
772 |
773 | } catch (error) {
774 | alert("Cannot process request due to: "+error.message);
775 | }
776 |
777 | },
778 |
779 | moveParamUp : function() {
780 | var treeChildren = document.getElementById("paramtreechildren");
781 | var indices = this.getAllSelectedIndices("paramtreechildren", "parameter-list" );
782 | //for ( var i = indices.length-1; i >= 0; i-- ) {
783 | for ( var i = 0; i < indices.length; i++ ) {
784 | var selectedParamIndex = indices[i];
785 | if ( selectedParamIndex >= 1 ) {
786 | var selectedTreeItem = treeChildren.childNodes[selectedParamIndex];
787 | var previousItem = treeChildren.childNodes[selectedParamIndex-1];
788 | treeChildren.removeChild(selectedTreeItem);
789 | treeChildren.insertBefore(selectedTreeItem, previousItem);
790 |
791 | var treeSelection = document.getElementById("parameter-list").view.selection;
792 | treeSelection.select(selectedParamIndex-1);
793 | }
794 | }
795 |
796 | this.updateUrlWithParams();
797 | },
798 |
799 |
800 | moveParamDown: function() {
801 | var treeChildren = document.getElementById("paramtreechildren");
802 | var indices = this.getAllSelectedIndices("paramtreechildren", "parameter-list" );
803 | for ( var i = indices.length-1; i >= 0; i-- ) {
804 | var selectedParamIndex = indices[i];
805 | if ( selectedParamIndex < treeChildren.childNodes.length - 1 ) {
806 | var selectedTreeItem = treeChildren.childNodes[selectedParamIndex];
807 | var nextItem = treeChildren.childNodes[selectedParamIndex+1];
808 | treeChildren.removeChild(nextItem);
809 | treeChildren.insertBefore( nextItem, selectedTreeItem);
810 | }
811 | }
812 | this.updateUrlWithParams();
813 | },
814 |
815 |
816 | sendContentToURL: function(urlstr,method,content,ctype) {
817 | try{
818 | if (this.inprogress) {
819 | var requestToCancel = this.inprogress;
820 | this.inprogress = null;
821 | requestToCancel.abort();
822 | }
823 | var currentApp = this;
824 | var timeout = parseInt(this.elements["timeout"].value)*1000;
825 | var username = this.elements["username"].value;
826 | var password = this.elements["password"].value;
827 |
828 |
829 | // create a Request
830 | var dateStamp = new Date().getTime();
831 | var transaction = new this.Transaction();
832 | transaction.timeStamp = dateStamp;
833 |
834 | var request = new this.RequestTransaction();
835 | request.httpMethod = method;
836 | request.url = urlstr;
837 | request.contentType = ctype;
838 | request.content = content;
839 | request.requestHeaders = this.getRequestHeadersFromUI();
840 | request.timeout = timeout;
841 | request.username = username;
842 | request.password = password;
843 | this.requestAdded( transaction, request );
844 | var headersToSend = this.getHeadersWithAuthorization(username, password, request);
845 |
846 | this.inprogress = HTTP(
847 | method,
848 | urlstr,
849 | {
850 | timeout: timeout,
851 | contentType: ctype,
852 | body: content,
853 | headers: headersToSend,
854 | username: username,
855 | password: password,
856 | id : transaction.timeStamp,
857 | returnHeaders: true,
858 | onOpened: function(request) {
859 | if (!currentApp.progressDialog) {
860 | currentApp.progressDialog = window.openDialog(
861 | 'chrome://httprequester/content/progress.xul','progress'+(new Date()).getTime(),'centerscreen,chrome,resizable',
862 | {
863 | url: urlstr,
864 | status: "Sending...",
865 | app: currentApp
866 | }
867 | );
868 | currentApp.progressDialog.focus();
869 | currentApp.receivingCount = 0;
870 | }
871 | },
872 | onHeaders: function(request) {
873 | currentApp.progressDialog.document.getElementById('status').value = 'Headers loaded...';
874 | },
875 | onLoading: function(request) {
876 | currentApp.receivingCount++;
877 | currentApp.progressDialog.document.getElementById('status').value = '('+currentApp.receivingCount+') Receiving...';
878 | },
879 | onSuccess: function(status,xml,text,headers,statusText, id) {
880 | currentApp.onResult(status,xml,text,headers,statusText, id);
881 | },
882 | onFailure: function(status,xml,text,headers,statusText, id) {
883 | currentApp.onResult(status,xml,text,headers,statusText, id);
884 | }
885 | }
886 | );
887 | } catch (error) {
888 | alert("Cannot process request due to: "+error.message);
889 | }
890 | },
891 | selectListItem: function() {
892 | var selectedTreeItemIndex = document.getElementById("transaction-list").currentIndex;
893 | if ( selectedTreeItemIndex >= 0 ) {
894 | var treeChildren = document.getElementById("transactiontreechildren");
895 | if ( treeChildren != null ) {
896 | if ( selectedTreeItemIndex >= treeChildren.childNodes.length ) {
897 | selectedTreeItemIndex = treeChildren.childNodes.length - 1;
898 | }
899 | var selectedTreeItem = treeChildren.childNodes[selectedTreeItemIndex];
900 | var transId = selectedTreeItem.getAttribute( "transactionID" );
901 | // get transaction for this id
902 | for (var i = 0; i < this.transactions.length; i++) {
903 | if (this.transactions[i].timeStamp == transId) {
904 | // found it
905 | this.updateUIForTransaction( this.transactions[i] );
906 | break;
907 | }
908 | }
909 | }
910 | }
911 | },
912 |
913 | updateUIForTransaction : function( transaction ) {
914 | this.initRequest(transaction.requestTransaction);
915 | if (transaction.responseTransaction != null) {
916 | Response.init(transaction.responseTransaction);
917 | }
918 | else {
919 | Response.clearResponseview();
920 | }
921 |
922 | },
923 | initRequest : function( request ) {
924 | this.elements["url"].value = request.url ? request.url : "";
925 | this.elements["filename"].value = request.filename ? request.filename : "";
926 | this.elements["contentType"].value = request.contentType ? request.contentType : "";
927 | this.elements["username"].value = request.username ? request.username : "";
928 | this.elements["password"].value = request.password ? request.password : "";
929 | this.elements["content"].value = request.content ? request.content : "";
930 | this.elements["timeout"].value = request.timeout ? request.timeout / 1000: "";
931 |
932 | // set tooltip text
933 | document.getElementById("tooltiptextval").setAttribute("value", request.url);
934 |
935 | var methodlist = document.getElementById("method");
936 | var items = methodlist.firstChild.childNodes;
937 | var count = methodlist.firstChild.childNodes.length;
938 | for (var i = 0; i < count; i++) {
939 | var methodItem = methodlist.firstChild.childNodes[i];
940 | if (methodItem.getAttribute('value') == request.httpMethod) {
941 | methodlist.selectedItem = methodItem;
942 | break;
943 | }
944 | }
945 |
946 |
947 | // update headers:
948 | // remove all headers:
949 | var treeChildren = document.getElementById("treechildren");
950 | if ( treeChildren != null && treeChildren.childNodes.length > 0 ) {
951 | while (treeChildren.hasChildNodes()) {
952 | treeChildren.removeChild(treeChildren.firstChild);
953 | }
954 | }
955 | for (var name in request.requestHeaders) {
956 | var value = request.requestHeaders[name];
957 | this.addRequestHeader(name, value);
958 | }
959 |
960 | this.updateParamsFromUri();
961 |
962 |
963 | },
964 | addTransactionToList: function( transaction ) {
965 | var item = null;
966 | var treeChildren = document.getElementById("transactiontreechildren");
967 | var treeItems = treeChildren.childNodes;
968 | if ( treeItems != null && treeItems.length >= this.getMaxHistory() ) {
969 | treeChildren.removeChild(treeItems[treeItems.length-1]);
970 | }
971 |
972 | try {
973 | var request = transaction.requestTransaction;
974 | var response = transaction.responseTransaction;
975 |
976 | var len = treeItems.length;
977 | var item = null;
978 |
979 | // adding new item
980 | if ( !item ) {
981 | item = document.createElement("treeitem");
982 | item.setAttribute( "transactionID", transaction.timeStamp );
983 | var newRow = document.createElement("treerow");
984 | item.appendChild(newRow);
985 | var nameCell = document.createElementNS(XUL_NS,"treecell");
986 | nameCell.setAttribute("label",request.httpMethod + " " + request.url);
987 | var valueCell = document.createElementNS(XUL_NS,"treecell");
988 | if (response != null) {
989 | valueCell.setAttribute("label", response.status + " " + response.statusText);
990 | }
991 | else {
992 | valueCell.setAttribute("label","");
993 | }
994 | var dateCell = document.createElementNS(XUL_NS,"treecell");
995 | dateCell.setAttribute("label",this.getDateString(transaction.timeStamp));
996 |
997 | // add Content length time:
998 | var contentLengthCell = document.createElementNS(XUL_NS,"treecell");
999 | var contentLength = 0;;
1000 | if (response != null && response.content != null ) {
1001 | // use Content-Length header if it was supplied by response
1002 | if ( response.responseHeaders != null && response.responseHeaders["Content-Length"] != null ) {
1003 | contentLength = response.responseHeaders["Content-Length"].trim();
1004 | }
1005 | else {
1006 | // otherwise use the length of the response body
1007 | contentLength = response.content.length;
1008 | }
1009 | }
1010 | // add B units (for bytes); similar to browser dev tools
1011 | contentLength = contentLength + " " + "B";
1012 | contentLengthCell.setAttribute("label",contentLength);
1013 |
1014 | // add elapsed time:
1015 | var elapsedTimeCell = document.createElementNS(XUL_NS,"treecell");
1016 | var elapsedTime = "";
1017 | if (transaction.timeStamp != null && response != null && response.responseTimeStamp != null) {
1018 | elapsedTime = (response.responseTimeStamp - transaction.timeStamp) + " ms";
1019 | }
1020 | elapsedTimeCell.setAttribute("label",elapsedTime);
1021 |
1022 | newRow.appendChild(nameCell);
1023 | newRow.appendChild(valueCell);
1024 | newRow.appendChild(dateCell);
1025 | newRow.appendChild(contentLengthCell);
1026 | newRow.appendChild(elapsedTimeCell);
1027 |
1028 | treeChildren.appendChild(item);
1029 | // insert item to the head of the list
1030 | if (len > 0) {
1031 | treeChildren.insertBefore(item, treeChildren.firstChild);
1032 | }
1033 | else {
1034 | treeChildren.appendChild(item);
1035 | }
1036 |
1037 | // make sure that newly selected row is shown in scroll pane
1038 | var tree = document.getElementById("transaction-list");
1039 | var boxobject = tree.boxObject;
1040 | boxobject.QueryInterface(Components.interfaces.nsITreeBoxObject);
1041 | // make sure it shows up at the top if possible
1042 | boxobject.scrollToRow(0);
1043 |
1044 | }
1045 |
1046 | } catch (ex) {
1047 | alert(ex);
1048 | }
1049 | },
1050 | getDateString : function( timeStamp ) {
1051 | var date = new Date(timeStamp);
1052 |
1053 | var m_names = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
1054 |
1055 | var dateStr = m_names[date.getMonth()] + " " + date.getDate() + " " + date.getFullYear();
1056 |
1057 |
1058 | // get time
1059 |
1060 |
1061 | var a_p = "";
1062 | var curr_hour = date.getHours();
1063 | if (curr_hour < 12)
1064 | {
1065 | a_p = "AM";
1066 | }
1067 | else
1068 | {
1069 | a_p = "PM";
1070 | }
1071 | if (curr_hour == 0)
1072 | {
1073 | curr_hour = 12;
1074 | }
1075 | if (curr_hour > 12)
1076 | {
1077 | curr_hour = curr_hour - 12;
1078 | }
1079 |
1080 | var curr_min = date.getMinutes();
1081 |
1082 | curr_min = curr_min + "";
1083 |
1084 | if (curr_min.length == 1)
1085 | {
1086 | curr_min = "0" + curr_min;
1087 | }
1088 |
1089 | var curr_sec = date.getSeconds();
1090 |
1091 | curr_sec = curr_sec + "";
1092 |
1093 | if (curr_sec.length == 1)
1094 | {
1095 | curr_sec = "0" + curr_sec;
1096 | }
1097 |
1098 |
1099 | dateStr = dateStr + " - " + curr_hour + ":" + curr_min + ":" + curr_sec + " " + a_p;
1100 |
1101 | return dateStr;
1102 |
1103 | },
1104 | editTransactionInList: function( transaction ) {
1105 | try {
1106 | var request = transaction.requestTransaction;
1107 | var response = transaction.responseTransaction;
1108 |
1109 |
1110 | var item = null;
1111 | var treeChildren = document.getElementById("transactiontreechildren");
1112 | var treeitems = treeChildren.childNodes;
1113 | var len = treeitems.length;
1114 |
1115 | // search based on timestamp
1116 | for (var i=0; i 0) {
1232 | for (var i = 0; i < this.contentTypeHistory.length; i++) {
1233 | if (request.contentType == this.contentTypeHistory[i]) {
1234 | this.removeElement(this.contentTypeHistory, i);
1235 | break;
1236 | }
1237 | }
1238 |
1239 | // add it to history
1240 | this.insertIntoArray(request.contentType, 0, this.contentTypeHistory, this.getMaxContentTypeHistory());
1241 |
1242 | // update menu
1243 | this.updateMenuList("ctype", this.contentTypeHistory);
1244 | }
1245 |
1246 | // update headers; go through each and add
1247 | var updated = false;
1248 | if ( request.requestHeaders != null ) {
1249 | for (var name in request.requestHeaders) {
1250 | for (var i = 0; i < this.headerNameHistory.length; i++) {
1251 | if (name == this.headerNameHistory[i]) {
1252 | this.removeElement(this.headerNameHistory, i);
1253 | break;
1254 | }
1255 | }
1256 | // add it to history
1257 | updated = true;
1258 | this.insertIntoArray(name, 0, this.headerNameHistory, this.getMaxHeaderHistory());
1259 | }
1260 |
1261 | if ( updated ) {
1262 | // update menu
1263 | this.updateMenuList("header-name", this.headerNameHistory);
1264 | }
1265 | }
1266 |
1267 | },
1268 |
1269 | updateMenuList : function( menuListName, listArray ) {
1270 | var urllist = document.getElementById(menuListName);
1271 | while ( urllist.firstChild.hasChildNodes()) {
1272 | urllist.firstChild.removeChild( urllist.firstChild.firstChild);
1273 | }
1274 |
1275 | for (var i = 0; i < listArray.length; i++) {
1276 | var newUrl = document.createElement("menuitem");
1277 | newUrl.setAttribute("label", listArray[i]);
1278 | newUrl.setAttribute("tooltiptext",listArray[i] )
1279 | urllist.firstChild.appendChild(newUrl);
1280 | }
1281 |
1282 | },
1283 |
1284 | getHeadersWithAuthorization: function (username, password, request) {
1285 | if ( username != null && username != "" && password != null ) {
1286 | var encoder = new Base64();
1287 | var encodedUserPass = encoder.encode(username + ":" + password);
1288 |
1289 | var headersToSend = {};
1290 | for (var i in request.requestHeaders) {
1291 | headersToSend[i] = request.requestHeaders[i];
1292 | }
1293 | // add Base64-encoded auth header
1294 | headersToSend[ "Authorization" ] = "Basic " + encodedUserPass;
1295 | return headersToSend;
1296 | }
1297 | else {
1298 | return request.requestHeaders;
1299 | }
1300 | },
1301 |
1302 | getContentFromURL: function(urlstr,method) {
1303 | try {
1304 | if (this.inprogress) {
1305 | var requestToCancel = this.inprogress;
1306 | this.inprogress = null;
1307 | requestToCancel.abort();
1308 | }
1309 | var currentApp = this;
1310 | var timeout = parseInt(this.elements["timeout"].value) * 1000;
1311 | var username = this.elements["username"].value;
1312 | var password = this.elements["password"].value;
1313 |
1314 |
1315 | // create a Request
1316 | var dateStamp = new Date().getTime();
1317 | var transaction = new this.Transaction();
1318 | transaction.timeStamp = dateStamp;
1319 |
1320 | var request = new this.RequestTransaction();
1321 | request.httpMethod = method;
1322 | request.url = urlstr;
1323 |
1324 | request.requestHeaders = this.getRequestHeadersFromUI();
1325 |
1326 | request.timeout = timeout;
1327 | request.username = username;
1328 | request.password = password;
1329 | this.requestAdded( transaction, request );
1330 | var headersToSend = this.getHeadersWithAuthorization(username, password, request);
1331 | // end create
1332 |
1333 |
1334 | this.inprogress = HTTP(
1335 | method,
1336 | urlstr,
1337 | {
1338 | timeout: timeout,
1339 | username: username,
1340 | password: password,
1341 | headers: headersToSend,
1342 | returnHeaders: true,
1343 | id : transaction.timeStamp,
1344 | onOpened: function(request) {
1345 | if (!currentApp.progressDialog) {
1346 | currentApp.progressDialog = window.openDialog(
1347 | 'chrome://httprequester/content/progress.xul','progress'+(new Date()).getTime(),'centerscreen,chrome,resizable',
1348 | {
1349 | url: urlstr,
1350 | status: "Sending...",
1351 | app: currentApp
1352 | }
1353 | );
1354 | currentApp.progressDialog.focus();
1355 | currentApp.receivingCount = 0;
1356 | }
1357 | },
1358 | onHeaders: function(request) {
1359 | currentApp.progressDialog.document.getElementById('status').value = 'Headers loaded...';
1360 | },
1361 | onLoading: function(request) {
1362 | currentApp.receivingCount++;
1363 | currentApp.progressDialog.document.getElementById('status').value = '('+currentApp.receivingCount+') Receiving...';
1364 | },
1365 | onSuccess: function(status,xml,text,headers,statusText, id) {
1366 | currentApp.onResult(status,xml,text,headers,statusText, id);
1367 | },
1368 | onFailure: function(status,xml,text,headers,statusText, id) {
1369 | currentApp.onResult(status,xml,text,headers,statusText, id);
1370 | }
1371 | }
1372 | );
1373 | } catch (error) {
1374 | alert("Cannot process request due to: "+error.message);
1375 | }
1376 | },
1377 |
1378 | // from the array: transactions
1379 | removeElement: function(transactions, index) {
1380 |
1381 | for (index = index; index origLength ) {
1394 | position = origLength;
1395 | }
1396 |
1397 | transactions.length = transactions.length + 1;
1398 |
1399 | for ( var i = origLength ; i >=0; i-- ) {
1400 | if ( i == position ) {
1401 | transactions[i] = transaction;
1402 | break;
1403 | }
1404 | else if ( i > position ) {
1405 | transactions[i] = transactions[i-1];
1406 | }
1407 | else if ( i < position ) {
1408 | break;
1409 | }
1410 | }
1411 |
1412 | if (transactions.length > maxcount) {
1413 | transactions.length=maxcount;
1414 | }
1415 |
1416 | },
1417 |
1418 |
1419 |
1420 | copyToClipBoard: function() {
1421 | var indices = this.getAllSelectedIndices("transactiontreechildren", "transaction-list" );
1422 | var transactionStr = "";
1423 | for ( var j = 0; j < indices.length; j++ ) {
1424 | if ( j != 0 ) {
1425 | transactionStr += '\n\n';
1426 | }
1427 | var selectedTreeItemIndex = indices[j];
1428 | transactionStr += this.getRequestAndResponseString(selectedTreeItemIndex);
1429 | }
1430 | this.copyText(transactionStr);
1431 | },
1432 | getSelectedTransactionId: function(index) {
1433 | var transId = null;
1434 | var selectedTreeItemIndex = index;
1435 | if ( selectedTreeItemIndex == null ) {
1436 | selectedTreeItemIndex = document.getElementById("transaction-list").currentIndex;
1437 | }
1438 | if ( selectedTreeItemIndex >= 0 ) {
1439 | var treeChildren = document.getElementById("transactiontreechildren");
1440 | if ( treeChildren != null ) {
1441 | if ( selectedTreeItemIndex >= treeChildren.childNodes.length ) {
1442 | selectedTreeItemIndex = treeChildren.childNodes.length - 1;
1443 | }
1444 | var selectedTreeItem = treeChildren.childNodes[selectedTreeItemIndex];
1445 | transId = selectedTreeItem.getAttribute( "transactionID" );
1446 | }
1447 | }
1448 | return transId;
1449 | },
1450 |
1451 |
1452 |
1453 | getRequestAndResponseString: function(index) {
1454 | // https://developer.mozilla.org/en/Using_the_Clipboard
1455 | var transactionStr = "";
1456 | var transaction = null;
1457 | var transId = this.getSelectedTransactionId(index);
1458 |
1459 | if ( transId != null ) {
1460 | for (var i = 0; i < this.transactions.length; i++) {
1461 | if (this.transactions[i].timeStamp == transId) {
1462 | // found it
1463 | transaction = this.transactions[i];
1464 | break;
1465 | }
1466 | }
1467 | }
1468 |
1469 | // get transaction for this id
1470 | if (transaction != null) {
1471 |
1472 | var request = transaction.requestTransaction;
1473 | var response = transaction.responseTransaction;
1474 |
1475 | //transactionStr += this.getDateString(transaction.timeStamp) + "\r\n";
1476 |
1477 | //transactionStr += "REQUEST ---> :" + "\r\n";
1478 | transactionStr += request.httpMethod + " " + request.url + "\n";
1479 |
1480 | //transactionStr += "Request Headers:" + "\r\n";
1481 | for (var name in request.requestHeaders) {
1482 | //transactionStr += " ";
1483 | transactionStr += name + ": " + request.requestHeaders[name] + "\n";
1484 | }
1485 | //transactionStr += "\n";
1486 |
1487 | if (request.contentType != null) {
1488 | transactionStr += "Content-Type: " + request.contentType + "\n";
1489 | }
1490 | if (request.filename != null) {
1491 | transactionStr += "Filename: " + request.filename + "\n";
1492 | }
1493 | if (request.username != null && request.username.length > 0 ) {
1494 | transactionStr += "Username: " + request.username + "\n";
1495 | }
1496 |
1497 | if (request.content != null) {
1498 | //transactionStr += "Request body:" + "\n";
1499 | transactionStr += request.content;
1500 | }
1501 | transactionStr += "\n";
1502 |
1503 | if (response != null) {
1504 | transactionStr += " -- response --" + "\n";
1505 | transactionStr += response.status + " " + response.statusText + "\n";
1506 | //transactionStr += "Response Headers:" + "\n";
1507 |
1508 | for (var name in response.responseHeaders) {
1509 | //transactionStr += " ";
1510 | transactionStr += name + ": " + response.responseHeaders[name] + "\n";
1511 | }
1512 | //transactionStr += "\n";
1513 | //transactionStr += "Response body:" + "\n";
1514 | if (response.content != null) {
1515 | transactionStr += "\n" + response.content;
1516 | }
1517 | transactionStr += "\n";
1518 | }
1519 | }
1520 | return transactionStr;
1521 | },
1522 | getRequestString: function() {
1523 | // https://developer.mozilla.org/en/Using_the_Clipboard
1524 | var transactionStr = "";
1525 | var transaction = null;
1526 | // get transaction for this id
1527 | var transId = this.getSelectedTransactionId();
1528 | if ( transId != null ) {
1529 | for (var i = 0; i < this.transactions.length; i++) {
1530 | if (this.transactions[i].timeStamp == transId) {
1531 | // found it
1532 | transaction = this.transactions[i];
1533 | break;
1534 | }
1535 | }
1536 | }
1537 |
1538 | if (transaction != null) {
1539 | var request = transaction.requestTransaction;
1540 | var response = transaction.responseTransaction;
1541 |
1542 | //transactionStr += this.getDateString(transaction.timeStamp) + "\n";
1543 |
1544 | //transactionStr += "REQUEST ---> :" + "\n";
1545 | transactionStr += request.httpMethod + " " + request.url + "\n";
1546 |
1547 | //transactionStr += "Request Headers:" + "\n";
1548 | for (var name in request.requestHeaders) {
1549 | //transactionStr += " ";
1550 | transactionStr += name + ": " + request.requestHeaders[name] + "\n";
1551 | }
1552 | //transactionStr += "\n";
1553 |
1554 | if (request.contentType != null) {
1555 | transactionStr += "Content-Type: " + request.contentType + "\n";
1556 | }
1557 | if (request.filename != null) {
1558 | transactionStr += "Filename: " + request.filename + "\n";
1559 | }
1560 | if (request.username != null && request.username.length > 0 ) {
1561 | transactionStr += "Username: " + request.username + "\n";
1562 | }
1563 |
1564 | if (request.content != null) {
1565 | //transactionStr += "Request body:" + "\n";
1566 | transactionStr += request.content;
1567 | }
1568 |
1569 | }
1570 | return transactionStr;
1571 | },
1572 |
1573 | editRawRequest: function() {
1574 | var requestStr = this.getRequestString();
1575 |
1576 | var newOptions = {
1577 | request: requestStr,
1578 | updatedRequest: ""
1579 | };
1580 | window.openDialog(
1581 | 'chrome://httprequester/content/request-entry.xul',
1582 | 'httprequester-request-entry'+(new Date()).getTime(),
1583 | "chrome,resizable,modal",
1584 | newOptions
1585 | );
1586 |
1587 | if (newOptions.updatedRequest != null && newOptions.updatedRequest.length > 0) {
1588 | this.executeRawRequest(newOptions.updatedRequest);
1589 | }
1590 |
1591 |
1592 | },
1593 |
1594 | saveStoredRequest: function() {
1595 | try {
1596 | var transaction = null;
1597 | // get transaction for this id
1598 | var transId = this.getSelectedTransactionId();
1599 |
1600 | // get transaction for this id
1601 | for (var i = 0; i < this.transactions.length; i++) {
1602 | if (this.transactions[i].timeStamp == transId) {
1603 | // found it
1604 | transaction = this.transactions[i];
1605 | var result = window.prompt("Add name for the stored request:\n" + transaction.requestTransaction.url);
1606 | if ( result != null ) {
1607 | var history = App.getPreferenceComplex("history.savedRequests");
1608 | var storedTransactions = new Array();
1609 |
1610 | if (history != null && history.length > 0) {
1611 | storedTransactions = JSON.parse(history);
1612 | }
1613 |
1614 | transaction.name = result;
1615 | this.insertIntoArray( transaction, 0, storedTransactions, 100 );
1616 | var storedHistoryString = JSON.stringify(storedTransactions);
1617 | this.setPreferenceComplex( "history.savedRequests", storedHistoryString );
1618 | }
1619 | break;
1620 | }
1621 | }
1622 |
1623 | } catch (ex) {
1624 | alert(ex);
1625 | }
1626 | },
1627 |
1628 | loadStoredRequest: function() {
1629 | var newOptions = {
1630 | selectedTransaction: null,
1631 | shouldExecute: false
1632 | };
1633 | window.openDialog(
1634 | 'chrome://httprequester/content/loadRequest.xul',
1635 | 'httprequester-request-entry'+(new Date()).getTime(),
1636 | "chrome,resizable,modal",
1637 | newOptions
1638 | );
1639 |
1640 | if (newOptions.selectedTransaction != null ) {
1641 | var storedTrans = JSON.parse(newOptions.selectedTransaction);
1642 | if ( newOptions.shouldExecute == true ) {
1643 | // user has chosen to execute the new request
1644 | // fill the UI with the new request
1645 | this.updateUIForTransaction(storedTrans);
1646 |
1647 | // execute request based on UI values
1648 | this.doMethodRequest();
1649 | }
1650 | else {
1651 | // simply load old stored request into list
1652 | this.insertIntoArray( storedTrans, 0, this.transactions, this.getMaxHistory() );
1653 | this.addTransactionToList(storedTrans);
1654 |
1655 | // select new entry in list
1656 | var treeSelection = document.getElementById("transaction-list").view.selection;
1657 | try {
1658 | treeSelection.select(0);
1659 | }
1660 | catch( e ) {
1661 | alert(ex);
1662 | }
1663 | }
1664 | }
1665 | },
1666 |
1667 | contentBodyRadioButtonChanged: function() {
1668 | var group = document.getElementById("contentBodyGroup");
1669 |
1670 | if ( group.selectedIndex == 0 ) {
1671 | document.getElementById("filename").setAttribute("disabled", "true");
1672 | document.getElementById("browse-file").setAttribute("disabled", "true");
1673 |
1674 | document.getElementById("content").removeAttribute("disabled" );
1675 | }
1676 | else {
1677 | document.getElementById("filename").removeAttribute("disabled" );
1678 | document.getElementById("browse-file").removeAttribute("disabled" );
1679 |
1680 | document.getElementById("content").setAttribute("disabled", "true");
1681 | }
1682 | },
1683 | responseRenderTypeChanged: function() {
1684 | if (this.initialized) { // don't run during xul startup load
1685 | var group = document.getElementById("responseRenderType");
1686 |
1687 | if (group.selectedIndex == 1) {
1688 | // text
1689 | this.setPreferenceBool("renderResponseBrowser", false);
1690 | document.getElementById("browserIframe").setAttribute("hidden", true);
1691 | document.getElementById("response-content").setAttribute("hidden", false);
1692 | }
1693 | else {
1694 | this.setPreferenceBool("renderResponseBrowser", true);
1695 | document.getElementById("browserIframe").setAttribute("hidden", false);
1696 | document.getElementById("response-content").setAttribute("hidden", true);
1697 | }
1698 | // refresh the selected item so that the response can be reloaded
1699 | // with the new pretty print option
1700 | App.selectListItem();
1701 | }
1702 | },
1703 | togglePrettyPrint: function() {
1704 | var oldPrettyPrint = this.getPreferenceBool("prettyPrintResponse");
1705 | var prettyPrint = !oldPrettyPrint;
1706 | this.setPreferenceBool("prettyPrintResponse", prettyPrint );
1707 |
1708 |
1709 | var prettyPrintCheckbox = document.getElementById("prettyPrint");
1710 | prettyPrintCheckbox.setAttribute("checked", prettyPrint);
1711 |
1712 | // refresh the selected item so that the response can be reloaded
1713 | // with the new pretty print option
1714 | App.selectListItem();
1715 | },
1716 |
1717 | viewRawRequest: function() {
1718 | var transaction = this.getRequestAndResponseString();
1719 |
1720 | var newOptions = {
1721 | request: transaction,
1722 | updatedRequest: ""
1723 | };
1724 | window.openDialog(
1725 | 'chrome://httprequester/content/request-entry.xul',
1726 | 'httprequester-request-entry'+(new Date()).getTime(),
1727 | "chrome,resizable,modal",
1728 | newOptions
1729 | );
1730 |
1731 | if (newOptions.updatedRequest != null && newOptions.updatedRequest.length > 0) {
1732 | this.executeRawRequest(newOptions.updatedRequest);
1733 | }
1734 |
1735 |
1736 | },
1737 | toggleAdvancedOptions: function() {
1738 | var hidden = document.getElementById("advancedSettings1").getAttribute("hidden");
1739 | if ( hidden != "true" ) {
1740 | document.getElementById("advancedSettings1").setAttribute("hidden", true);
1741 | document.getElementById("advancedSettings2").setAttribute("hidden", true);
1742 | }
1743 | else {
1744 | document.getElementById("advancedSettings1").setAttribute("hidden", false);
1745 | document.getElementById("advancedSettings2").setAttribute("hidden", false);
1746 | }
1747 | },
1748 |
1749 | pasteRawRequest: function() {
1750 | var requestStr = this.copyTextfromClipboard();
1751 | var newOptions = {
1752 | request: requestStr,
1753 | updatedRequest: ""
1754 | };
1755 | window.openDialog(
1756 | 'chrome://httprequester/content/request-entry.xul',
1757 | 'httprequester-request-entry'+(new Date()).getTime(),
1758 | "chrome,resizable,modal",
1759 | newOptions
1760 | );
1761 |
1762 | if (newOptions.updatedRequest != null && newOptions.updatedRequest.length > 0) {
1763 | this.executeRawRequest(newOptions.updatedRequest);
1764 | }
1765 | },
1766 | trim: function(s) {
1767 | if ( s != null && s.length > 0 ) {
1768 | // Remove leading spaces and carriage returns
1769 | while ((s.substring(0,1) == ' ') ) {
1770 | s = s.substring(1,s.length);
1771 | }
1772 |
1773 | // Remove trailing spaces and carriage returns
1774 | while ((s.substring(s.length-1,s.length) == ' ') ) {
1775 | s = s.substring(0,s.length-1);
1776 | }
1777 | }
1778 |
1779 | return s;
1780 | },
1781 | getMethod: function (readIn ) {
1782 | var method = null;
1783 | if (readIn.indexOf("GET") == 0) {
1784 | method = "GET";
1785 | }
1786 | else if (readIn.indexOf("POST") == 0) {
1787 | method = "POST";
1788 | }
1789 | else if (readIn.indexOf("PUT") == 0) {
1790 | method = "PUT";
1791 | }
1792 | else if (readIn.indexOf("DELETE") == 0) {
1793 | method = "DELETE";
1794 | }
1795 | else if (readIn.indexOf("HEAD") == 0) {
1796 | method = "HEAD";
1797 | }
1798 | else if (readIn.indexOf("OPTIONS") == 0) {
1799 | method = "OPTIONS";
1800 | }
1801 | else if (readIn.indexOf("PATCH") == 0) {
1802 | method = "PATCH";
1803 | }
1804 | else {
1805 | // load custom methods
1806 | var sendCommands = this.getPreferenceString("http.methods.custom.write");
1807 | if (sendCommands != null && sendCommands.length > 0) {
1808 | this.customWriteHttpMethods = JSON.parse(sendCommands);
1809 | }
1810 | else {
1811 | this.customWriteHttpMethods = new Array();
1812 | }
1813 | var readCommands = this.getPreferenceString("http.methods.custom.read");
1814 | if (readCommands != null && readCommands.length > 0) {
1815 | this.customReadHttpMethods = JSON.parse(readCommands);
1816 | }
1817 | else {
1818 | this.customReadHttpMethods = new Array();
1819 | }
1820 |
1821 | // populate METHOD dropdown with custom methods
1822 | for (var i = 0; i < this.customWriteHttpMethods.length && method == null; i++) {
1823 | if (readIn.indexOf(this.customWriteHttpMethods[i]) == 0) {
1824 | method = this.customWriteHttpMethods[i];
1825 | }
1826 | }
1827 | for (var i = 0; i < this.customReadHttpMethods.length && method == null; i++) {
1828 | if (readIn.indexOf(this.customReadHttpMethods[i]) == 0) {
1829 | method = this.customReadHttpMethods[i];
1830 | }
1831 | }
1832 |
1833 | if ( method == null ) {
1834 | method = readIn;
1835 | }
1836 | }
1837 | return method;
1838 | },
1839 | executeRawRequest: function( requestStr ) {
1840 | // create a Request
1841 | var dateStamp = new Date().getTime();
1842 | var transaction = new this.Transaction();
1843 | transaction.timeStamp = dateStamp;
1844 |
1845 | var request = new this.RequestTransaction();
1846 | // request.timeout = timeout;
1847 | // request.username = username;
1848 | // request.password = password;
1849 |
1850 | var text = requestStr;
1851 | this.clearRequestView();
1852 | Response.clearResponseview();
1853 | if (text != null) {
1854 |
1855 | // if the request string actually contains the response as well
1856 | var responseStartIndex = text.lastIndexOf( "\n\n -- response --" );
1857 | if ( responseStartIndex != -1 ) {
1858 | text = text.substring(0, responseStartIndex);
1859 | }
1860 |
1861 | var uri = null;
1862 | var textLines = this.splitOnAllNewlines(text);
1863 | var index = 0;
1864 | var readIn = textLines[index];
1865 | var method = this.getMethod(readIn);
1866 | if (method == null) {
1867 | // first line may be URI
1868 | if (readIn.indexOf("http") == 0) {
1869 | uri = this.trim(readIn);
1870 | }
1871 | while (index < textLines.length && method == null) {
1872 | index = index + 1;
1873 | readIn = textLines[index];
1874 | method = this.getMethod(readIn);
1875 | }
1876 | }
1877 |
1878 | if (uri == null) {
1879 | var endIndex = readIn.lastIndexOf("HTTP");
1880 | if (endIndex == -1) {
1881 | endIndex = readIn.length;
1882 | }
1883 | var beginIndex = method.length;
1884 | uri = this.trim(readIn.substring(beginIndex, endIndex));
1885 | }
1886 |
1887 | if (uri != null && uri.indexOf("http") != 0) {
1888 | // uri is not of type:
1889 | // GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
1890 | // but of:
1891 | // GET /pub/WWW/TheProject.html HTTP/1.1
1892 | // Host: www.w3.org
1893 | index = index + 1;
1894 | readIn = textLines[index];
1895 | if (readIn.indexOf("Host:") == 0) {
1896 | var host = this.trim(readIn.substring("Host:".length));
1897 |
1898 | var defaultProtocol = this.getPreferenceString("default.protocol");
1899 | if ( defaultProtocol == null || defaultProtocol.length == 0 ) {
1900 | defaultProtocol = "https";
1901 | }
1902 | uri = defaultProtocol + "://" + host + uri;
1903 | }
1904 | else {
1905 | // Host was not the next line - something not right; roll back to previous line and try to continue
1906 | index--;
1907 | }
1908 | }
1909 |
1910 | var requestHeadersFromUI = {};
1911 |
1912 | index = index + 1;
1913 | var inBody = false;
1914 | var content = "";
1915 | while (index < textLines.length) {
1916 | readIn = textLines[index];
1917 | if (!inBody) {
1918 | var colonIndex = readIn.indexOf(": ");
1919 | // looking for headers by checking for a word followed by a colon then a space:
1920 | // example:
1921 | // Accept: none
1922 | // Keep-Alive: 115
1923 | if (colonIndex != -1) {
1924 | var spaceCheck = readIn.indexOf(" ");
1925 | if (spaceCheck == -1 || spaceCheck > colonIndex) {
1926 | // add header
1927 | var name = readIn.substring(0,colonIndex);
1928 | var value = readIn.substring( colonIndex + ": ".length );
1929 | if ("Content-Type"==name) {
1930 | request.contentType = value;
1931 | }
1932 | else {
1933 | requestHeadersFromUI[name] = value;
1934 | }
1935 | }
1936 | else {
1937 | inBody = true;
1938 | }
1939 | }
1940 | else {
1941 | inBody = true;
1942 | }
1943 | }
1944 | if (inBody ) {
1945 | // add to text body
1946 | content = content + readIn;
1947 | if ( index + 1 < textLines.length ) {
1948 | content += "\n";
1949 | }
1950 | }
1951 | index++;
1952 | }
1953 | request.url = uri;
1954 | request.httpMethod = method;
1955 | request.content = content;
1956 | request.requestHeaders = requestHeadersFromUI;
1957 | transaction.requestTransaction = request;
1958 |
1959 | // fill the UI with the new request
1960 | this.updateUIForTransaction(transaction);
1961 |
1962 | // execute the new request based on UI values
1963 | this.doMethodRequest();
1964 |
1965 | }
1966 | },
1967 |
1968 |
1969 | copyTextfromClipboard : function () {
1970 | // =========================================================================
1971 | var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
1972 | if (!clip) return null;
1973 |
1974 | var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
1975 | if (!trans) return null;
1976 |
1977 | trans.addDataFlavor("text/unicode");
1978 |
1979 | clip.getData(trans, clip.kGlobalClipboard);
1980 |
1981 | var str = new Object();
1982 | var strLength = new Object();
1983 |
1984 | try { // 'try' to prevent error with empty or non-text clipboard content
1985 | trans.getTransferData("text/unicode", str, strLength);
1986 |
1987 | if (str) str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
1988 | if (str) pastetext = str.data.substring(0, strLength.value / 2);
1989 |
1990 | if (pastetext != "") return pastetext;
1991 | } catch (ex) {};
1992 | return null;
1993 | },
1994 |
1995 |
1996 | copyText: function( copytext) {
1997 | var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
1998 | if (!str)
1999 | return false;
2000 |
2001 | str.data = copytext;
2002 |
2003 | var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
2004 | if (!trans)
2005 | return false;
2006 |
2007 | trans.addDataFlavor("text/unicode");
2008 | trans.setTransferData("text/unicode", str, copytext.length * 2);
2009 |
2010 | var clipid = Components.interfaces.nsIClipboard;
2011 | var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
2012 | if (!clip)
2013 | return false;
2014 |
2015 | clip.setData(trans, null, clipid.kGlobalClipboard);
2016 | },
2017 |
2018 | clearHistory: function() {
2019 | // clear list
2020 | this.transactions = new Array();
2021 |
2022 | // clear list
2023 | var treeChildren = document.getElementById("transactiontreechildren");
2024 | if ( treeChildren != null && treeChildren.childNodes.length > 0 ) {
2025 | while (treeChildren.hasChildNodes()) {
2026 | treeChildren.removeChild(treeChildren.firstChild);
2027 | }
2028 | }
2029 | },
2030 |
2031 | makeParameterPost: function() {
2032 | this.elements["contentType"].value = "application/x-www-form-urlencoded";
2033 | var body = "";
2034 | var parameters = this.getParametersFromUI();
2035 |
2036 | // now remove the parameters from the UI; don't want them to get added to the
2037 | // request URI on submit
2038 | var treeChildren = document.getElementById("paramtreechildren");
2039 | if ( treeChildren != null && treeChildren.childNodes.length > 0 ) {
2040 | while (treeChildren.hasChildNodes()) {
2041 | treeChildren.removeChild(treeChildren.firstChild);
2042 | }
2043 | }
2044 |
2045 | for (var name in parameters) {
2046 | var valArray = parameters[name];
2047 | for ( var i = 0; i < valArray.length; i++ ) {
2048 | var paramValue = valArray[i];
2049 |
2050 |
2051 | if (body.length > 0) {
2052 | body += "&";
2053 | }
2054 |
2055 | var val = encodeURIComponent(paramValue);
2056 | if (val != null && val.length > 0) {
2057 | body += name + "=" + val;
2058 | }
2059 | else {
2060 | body += name;
2061 | }
2062 | }
2063 | }
2064 | this.elements["content"].value = body;
2065 |
2066 | // update URL, as the params have been removed from URI to go to the form body
2067 | this.updateUrlWithParams();
2068 | },
2069 | clearRequest : function() {
2070 | this.clearRequestView();
2071 | Response.clearResponseview();
2072 |
2073 | },
2074 | splitOnAllNewlines : function(input) {
2075 | // just use common newline to read in lines - check for strings that end in \r (to handle windows \r\n)
2076 | var newline = "\n";
2077 | var returnLine = "\r";
2078 |
2079 | var remindersArray = input.split(newline);
2080 | var returnArray = new Array();
2081 | var returnArrayIndex = 0;
2082 | for ( var index = 0; index < remindersArray.length; index++ ) {
2083 | var readIn = remindersArray[index];
2084 | /* --------
2085 | if (readIn.length > 0 && readIn.lastIndexOf(returnLine) == readIn.length -1 ) {
2086 | readIn = readIn.substring(0, readIn.length -1 );
2087 | } ---- */
2088 | while (readIn.length > 0 && readIn.lastIndexOf(returnLine) == readIn.length -1 ) {
2089 | readIn = readIn.substring(0, readIn.length -1 );
2090 | }
2091 |
2092 | returnArray[returnArrayIndex] = readIn;
2093 | returnArrayIndex++;
2094 | }
2095 | return returnArray;
2096 | },
2097 | clearRequestView : function() {
2098 | this.elements["url"].value = "";
2099 | this.elements["filename"].value = "";
2100 | this.elements["contentType"].value = "";
2101 | this.elements["username"].value = "";
2102 | this.elements["password"].value = "";
2103 | this.elements["content"].value = "";
2104 | this.elements["timeout"].value = "";
2105 |
2106 | var methodlist = document.getElementById("method");
2107 | var items = methodlist.firstChild.childNodes;
2108 | var count = methodlist.firstChild.childNodes.length;
2109 |
2110 | // document.getElementById("base64-encode").onclick = function() {
2111 | // var value = current.elements["content"].value;
2112 | // if (value.length>0) {
2113 | // var encoder = new Base64();
2114 | // current.elements["content"].value = encoder.encode(value);
2115 | // }
2116 |
2117 | // update headers:
2118 | // remove all headers:
2119 | var treeChildren = document.getElementById("treechildren");
2120 | if ( treeChildren != null && treeChildren.childNodes.length > 0 ) {
2121 | while (treeChildren.hasChildNodes()) {
2122 | treeChildren.removeChild(treeChildren.firstChild);
2123 | }
2124 | }
2125 |
2126 | // remove parameters
2127 | treeChildren = document.getElementById("paramtreechildren");
2128 | if ( treeChildren != null && treeChildren.childNodes.length > 0 ) {
2129 | while (treeChildren.hasChildNodes()) {
2130 | treeChildren.removeChild(treeChildren.firstChild);
2131 | }
2132 | }
2133 |
2134 | },
2135 | onAddChangeHeader: function() {
2136 | var name = document.getElementById("header-name").value;
2137 | if (!name) {
2138 | return;
2139 | }
2140 | var value = document.getElementById("header-value").value;
2141 | //this.requestHeaders[name] = value;
2142 | this.addRequestHeader(name,value);
2143 | },
2144 | getAllSelectedIndices : function( treechildren, tree) {
2145 | var treeChildren = document.getElementById(treechildren);
2146 | var indices = new Array();
2147 |
2148 | var start = new Object();
2149 | var end = new Object();
2150 | var numRanges = document.getElementById(tree).view.selection.getRangeCount();
2151 |
2152 | for (var t = 0; t < numRanges; t++){
2153 | document.getElementById(tree).view.selection.getRangeAt(t,start,end);
2154 | for (var v = start.value; v <= end.value; v++){
2155 | indices[indices.length] = v;
2156 | }
2157 | }
2158 |
2159 | return indices;
2160 | },
2161 | selectHeader :function (event) {
2162 | // when a header is selected in the list, we will update the name/value text fields as well
2163 | // so they can easily be edited
2164 | var selectedTreeItemIndex = document.getElementById("header-list").currentIndex;
2165 | if ( selectedTreeItemIndex >= 0 ) {
2166 | var treeChildren = document.getElementById("treechildren");
2167 | if ( treeChildren != null ) {
2168 | if ( selectedTreeItemIndex >= treeChildren.childNodes.length ) {
2169 | selectedTreeItemIndex = treeChildren.childNodes.length - 1;
2170 | }
2171 | var selectedTreeItem = treeChildren.childNodes[selectedTreeItemIndex];
2172 | if ( selectedTreeItem != null ) {
2173 | var nameCell = selectedTreeItem.getElementsByTagName('treecell').item(0);
2174 | var valueCell = selectedTreeItem.getElementsByTagName('treecell').item(1);
2175 | var headername = nameCell.getAttribute('label');
2176 | var headervalue = valueCell.getAttribute('label');
2177 |
2178 | document.getElementById("header-name").value = headername;
2179 | document.getElementById("header-value").value = headervalue;
2180 | }
2181 | }
2182 | }
2183 |
2184 | },
2185 | addRequestHeader: function(name,value) {
2186 | var item = null;
2187 | var treeChildren = document.getElementById("treechildren");
2188 | var treeitems = treeChildren.childNodes;
2189 |
2190 | try {
2191 | for (var i=0; i < treeitems.length; i++) {
2192 | item = treeitems[i];
2193 | var nameCell = item.getElementsByTagName('treecell').item(0);
2194 | if (nameCell.getAttribute('label')==name) {
2195 | break;
2196 | }
2197 | item = null;
2198 | }
2199 |
2200 | // adding new item
2201 | if ( !item ) {
2202 | var treeChildren = document.getElementById("treechildren");
2203 | var newItem = document.createElement("treeitem");
2204 | var newRow = document.createElement("treerow");
2205 | var nameLabel = document.createElement("treecell");
2206 | var valLabel = document.createElement("treecell");
2207 | newItem.appendChild(newRow);
2208 | newRow.appendChild(nameLabel);
2209 | newRow.appendChild(valLabel);
2210 | nameLabel.setAttribute("label", name);
2211 | valLabel.setAttribute("label", value);
2212 | treeChildren.appendChild(newItem);
2213 | }
2214 | else {
2215 | // updating existing item
2216 | var cells = item.getElementsByTagName('treecell');
2217 | var nameCell = cells.item(0);
2218 | var valueCell = cells.item(1);
2219 | nameCell.setAttribute("label",name);
2220 | valueCell.setAttribute("label",value);
2221 | }
2222 |
2223 | } catch (ex) {
2224 | alert(ex);
2225 | }
2226 |
2227 |
2228 | },
2229 | onDeleteHeader: function() {
2230 | var treeChildren = document.getElementById("treechildren");
2231 | var indices = this.getAllSelectedIndices("treechildren", "header-list" );
2232 | for ( var i = indices.length-1; i >= 0; i-- ) {
2233 | var index = indices[i];
2234 | var selectedTreeItem = treeChildren.childNodes[index];
2235 | if (selectedTreeItem != null) {
2236 | treeChildren.removeChild(selectedTreeItem);
2237 | }
2238 | }
2239 | },
2240 |
2241 | getRequestHeadersFromUI : function() {
2242 | var requestHeadersFromUI = {};
2243 |
2244 | var item = null;
2245 | var treeChildren = document.getElementById("treechildren");
2246 | var treeitems = treeChildren.childNodes;
2247 |
2248 | try {
2249 | for (var i=0; i < treeitems.length; i++) {
2250 | item = treeitems[i];
2251 | var cells = item.getElementsByTagName('treecell');
2252 | var nameCell = cells.item(0);
2253 | var name = nameCell.getAttribute('label');
2254 | var valueCell = cells.item(1);
2255 | var value = valueCell.getAttribute('label');
2256 | requestHeadersFromUI[name] = value;
2257 | }
2258 | } catch (ex) {
2259 | alert(ex);
2260 | }
2261 | return requestHeadersFromUI;
2262 | },
2263 |
2264 |
2265 | onAddChangeParameter: function() {
2266 | var name = document.getElementById("parameter-name").value;
2267 | if (!name) {
2268 | return;
2269 | }
2270 | var value = document.getElementById("parameter-value").value;
2271 | this.addParameter(name,value);
2272 |
2273 | this.updateUrlWithParams();
2274 |
2275 |
2276 | },
2277 | addParameter: function(name,value) {
2278 | var item = null;
2279 | var treeChildren = document.getElementById("paramtreechildren");
2280 | var treeitems = treeChildren.childNodes;
2281 |
2282 | try {
2283 | // You can have multiple parameters - so we won't update existing ones; this can be done
2284 | // via direct editing of cells
2285 | // for (var i=0; i < treeitems.length; i++) {
2286 | // item = treeitems[i];
2287 | // var nameCell = item.getElementsByTagName('treecell').item(0);
2288 | // if (nameCell.getAttribute('label')==name) {
2289 | // break;
2290 | // }
2291 | // item = null;
2292 | // }
2293 |
2294 | if ( value == null ) {
2295 | value = "";
2296 | }
2297 |
2298 | // adding new item
2299 | if ( !item ) {
2300 | var treeChildren = document.getElementById("paramtreechildren");
2301 | var newItem = document.createElement("treeitem");
2302 | var newRow = document.createElement("treerow");
2303 | var nameLabel = document.createElement("treecell");
2304 | var valLabel = document.createElement("treecell");
2305 | newItem.appendChild(newRow);
2306 | newRow.appendChild(nameLabel);
2307 | newRow.appendChild(valLabel);
2308 | nameLabel.setAttribute("label", name);
2309 | valLabel.setAttribute("label", value);
2310 | treeChildren.appendChild(newItem);
2311 | }
2312 | else {
2313 | // updating existing item
2314 | var cells = item.getElementsByTagName('treecell');
2315 | var nameCell = cells.item(0);
2316 | var valueCell = cells.item(1);
2317 | nameCell.setAttribute("label",name);
2318 | valueCell.setAttribute("label",value);
2319 | }
2320 |
2321 | } catch (ex) {
2322 | alert(ex);
2323 | }
2324 | },
2325 | getParametersFromUI : function() {
2326 | var parametersFromUI = {};
2327 |
2328 | var item = null;
2329 | var treeChildren = document.getElementById("paramtreechildren");
2330 | var treeitems = treeChildren.childNodes;
2331 |
2332 | try {
2333 | for (var i=0; i < treeitems.length; i++) {
2334 | item = treeitems[i];
2335 | var cells = item.getElementsByTagName('treecell');
2336 | var nameCell = cells.item(0);
2337 | var name = nameCell.getAttribute('label');
2338 | var valueCell = cells.item(1);
2339 | var value = valueCell.getAttribute('label');
2340 |
2341 | var valArray = parametersFromUI[name];
2342 | if ( !valArray ) {
2343 | valArray = [];
2344 | }
2345 | valArray[valArray.length] = value;
2346 |
2347 | parametersFromUI[name] = valArray;
2348 | }
2349 | } catch (ex) {
2350 | alert(ex);
2351 | }
2352 | return parametersFromUI;
2353 | },
2354 |
2355 | onDeleteTransaction: function() {
2356 | var indices = this.getAllSelectedIndices("transactiontreechildren", "transaction-list" );
2357 | for ( var j = indices.length-1; j >= 0; j-- ) {
2358 | var selectedTreeItemIndex = indices[j];
2359 |
2360 | try {
2361 | var transaction = null;
2362 | if ( selectedTreeItemIndex >= 0 ) {
2363 | var treeChildren = document.getElementById("transactiontreechildren");
2364 | if ( treeChildren != null ) {
2365 | if ( selectedTreeItemIndex >= treeChildren.childNodes.length ) {
2366 | selectedTreeItemIndex = treeChildren.childNodes.length - 1;
2367 | }
2368 | var selectedTreeItem = treeChildren.childNodes[selectedTreeItemIndex];
2369 | var transId = selectedTreeItem.getAttribute( "transactionID" );
2370 | // get transaction for this id
2371 | for (var i = 0; i < this.transactions.length; i++) {
2372 | if (this.transactions[i].timeStamp == transId) {
2373 | // found it
2374 | transaction = this.transactions[i];
2375 | this.removeElement(this.transactions, i);
2376 |
2377 | treeChildren.removeChild(selectedTreeItem);
2378 |
2379 | this.clearRequest();
2380 | break;
2381 | }
2382 | }
2383 | }
2384 | }
2385 | } catch (ex) {
2386 | alert(ex);
2387 | }
2388 | }
2389 | },
2390 | onDeleteParameter: function() {
2391 | var treeChildren = document.getElementById("paramtreechildren");
2392 | var indices = this.getAllSelectedIndices("paramtreechildren", "parameter-list" );
2393 | for ( var i = indices.length-1; i >= 0; i-- ) {
2394 | var index = indices[i];
2395 | var selectedTreeItem = treeChildren.childNodes[index];
2396 | if (selectedTreeItem != null) {
2397 | treeChildren.removeChild(selectedTreeItem);
2398 | }
2399 | }
2400 | this.updateUrlWithParams();
2401 | }
2402 | }
2403 |
2404 |
--------------------------------------------------------------------------------
/src/content/loadRequest.js:
--------------------------------------------------------------------------------
1 | var LoadRequest = {
2 | savedHistoryTransactions : null,
3 |
4 | load: function() {
5 | var history = App.getPreferenceComplex("history.savedRequests");
6 | if (history != null && history.length > 0) {
7 | savedHistoryTransactions = JSON.parse(history);
8 |
9 | var saved_requests_listbox= document.getElementById("saved_requests_listbox");
10 | // clear existing list items
11 | while (saved_requests_listbox.hasChildNodes()) {
12 | saved_requests_listbox.removeChild(saved_requests_listbox.firstChild);
13 | }
14 |
15 | for (var i = 0; i < savedHistoryTransactions.length; i++) {
16 | var newItem = document.createElement("listitem");
17 | var dateStr = App.getDateString(savedHistoryTransactions[i].timeStamp);
18 | newItem.setAttribute( "label", savedHistoryTransactions[i].name + ": " + savedHistoryTransactions[i].requestTransaction.url + " (" + dateStr + ")");
19 | saved_requests_listbox.appendChild(newItem);
20 | }
21 | }
22 | },
23 |
24 | selectSavedTransaction: function(shouldExecuteRequest) {
25 | var saved_requests_listbox= document.getElementById("saved_requests_listbox");
26 | var index = saved_requests_listbox.selectedIndex;;
27 | window.arguments[0].selectedTransaction = JSON.stringify(savedHistoryTransactions[index]);
28 | window.arguments[0].shouldExecute = shouldExecuteRequest;
29 | window.close();
30 | },
31 |
32 | remove: function() {
33 | var saved_requests_listbox= document.getElementById("saved_requests_listbox");
34 | var index = saved_requests_listbox.selectedIndex;;
35 | var item = saved_requests_listbox.getItemAtIndex(index);
36 | App.removeElement(savedHistoryTransactions, index);
37 | saved_requests_listbox.removeItemAt(saved_requests_listbox.getIndexOfItem(item));
38 |
39 | // write out updated pref store
40 | var storedHistoryString = JSON.stringify(savedHistoryTransactions);
41 | App.setPreferenceComplex( "history.savedRequests", storedHistoryString );
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/src/content/loadRequest.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/content/overlay.js:
--------------------------------------------------------------------------------
1 | if (!httprequester) var httprequester = {};
2 |
3 | httprequester.showHttpRequester = function () {
4 | var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
5 | var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
6 | var topWindow = windowManagerInterface.getMostRecentWindow("window:httprequester");
7 | if (topWindow) {
8 | try {
9 | topWindow.focus();
10 | } catch (e) {}
11 | } else {
12 | window.openDialog(
13 | 'chrome://httprequester/content/httprequester-window.xul',
14 | 'httprequester-' + (new Date()).getTime(),
15 | 'chrome,centerscreen,resizable,dialog=no'
16 | );
17 | }
18 | };
19 |
20 | httprequester.initialize = function () {
21 | // run this later and let the window load.
22 | window.setTimeout(function () {
23 | httprequester.start();
24 | }, 100);
25 | }
26 |
27 | httprequester.start = function () {
28 | var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces
29 | .nsIPrefService).getBranch("extensions.httprequester.");
30 | if (preferencesService) {
31 | var firstrun = true;
32 | try {
33 | firstrun = preferencesService.getBoolPref("firstrun");
34 | } catch (e) {
35 | firstrun = true;
36 | }
37 | var curVersion = "2.1";
38 |
39 |
40 | if (firstrun) {
41 | preferencesService.setBoolPref("firstrun", false);
42 | preferencesService.setCharPref("installedVersion", curVersion);
43 | /* Code related to firstrun */
44 |
45 | httprequester.installButton("nav-bar", "http-requester-button");
46 | // The "addon-bar" is available since Firefox 4
47 | //httprequester.installButton("addon-bar", "my-extension-addon-bar-button");
48 |
49 | } else {
50 | try {
51 | var installedVersion = preferencesService.getCharPref("installedVersion");
52 | if (curVersion > installedVersion) {
53 | preferencesService("installedVersion", curVersion);
54 | /* Code related to upgrade */
55 | }
56 | } catch (ex) {
57 | /* Code related to a reinstall */
58 | }
59 | }
60 | }
61 | };
62 |
63 |
64 | /**
65 | * Installs the toolbar button with the given ID into the given
66 | * toolbar, if it is not already present in the document.
67 | *
68 | * @param {string} toolbarId The ID of the toolbar to install to.
69 | * @param {string} id The ID of the button to install.
70 | * @param {string} afterId The ID of the element to insert after. @optional
71 | */
72 | httprequester.installButton = function (toolbarId, id, afterId) {
73 | if (!document.getElementById(id)) {
74 | var toolbar = document.getElementById(toolbarId);
75 |
76 | // If no afterId is given, then append the item to the toolbar
77 | var before = null;
78 | if (afterId) {
79 | let elem = document.getElementById(afterId);
80 | if (elem && elem.parentNode == toolbar)
81 | before = elem.nextElementSibling;
82 | }
83 |
84 | toolbar.insertItem(id, before);
85 | toolbar.setAttribute("currentset", toolbar.currentSet);
86 | document.persist(toolbar.id, "currentset");
87 |
88 | if (toolbarId == "addon-bar")
89 | toolbar.collapsed = false;
90 | }
91 | }
--------------------------------------------------------------------------------
/src/content/overlay.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
10 | -
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/content/progress.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/content/request-entry.js:
--------------------------------------------------------------------------------
1 | var RequestEntry = {
2 | lastSearchString : "",
3 |
4 | loadRequest: function(){
5 | var requestStr = window.arguments[0].request;
6 | if (requestStr != null && requestStr.length > 0) {
7 | document.getElementById("content").value = requestStr;
8 | }
9 | },
10 | pasteFromClipboard: function() {
11 | var text = App.copyTextfromClipboard();
12 | document.getElementById("content").value = text;
13 | },
14 | findInTextBox : function() {
15 | var nsIPromptService = Components.interfaces.nsIPromptService;
16 | var nsPrompt_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1";
17 | var gPromptService = Components.classes[nsPrompt_CONTRACTID].getService(nsIPromptService);
18 | var result = { value: this.lastSearchString };
19 | var dummy = { value: 0 };
20 |
21 | if (gPromptService.prompt(window,
22 | "Find text in transaction",
23 | "Enter text to search for:",
24 | result,
25 | null,
26 | dummy)) {
27 | this.lastSearchString = result.value;
28 |
29 | this.doFindNext();
30 | }
31 | },
32 | doFindNext : function() {
33 | var text = document.getElementById("content").value;
34 |
35 | var start = document.getElementById("content").selectionStart;
36 |
37 | if ( start < text.length - 1 ) {
38 | start = start + 1;
39 | }
40 | var index = text.toUpperCase().indexOf( this.lastSearchString.toUpperCase(), start );
41 | if ( index == -1 ) {
42 | // restart; look from the beginning
43 | index = text.toUpperCase().indexOf( this.lastSearchString.toUpperCase() );
44 | }
45 | if ( index == -1 ) {
46 | alert( "No match found.");
47 | }
48 | else {
49 | document.getElementById("content").select();
50 | document.getElementById("content").setSelectionRange(index, (index + this.lastSearchString.length));
51 | }
52 |
53 | },
54 | doRequest: function(){
55 | window.arguments[0].updatedRequest = document.getElementById("content").value;
56 | window.close();
57 | }
58 |
59 | }
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/content/request-entry.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/defaults/preferences/defaults.js:
--------------------------------------------------------------------------------
1 | pref("extensions.httprequester.maxhistory", 45);
2 | pref("extensions.httprequester.url.maxhistory", 15);
3 | pref("extensions.httprequester.contenttype.maxhistory", 15);
4 | pref("extensions.httprequester.header.maxhistory", 15);
5 |
6 | pref("extensions.httprequester.history", "");
7 | pref("extensions.httprequester.url.history", "");
8 | pref("extensions.httprequester.history.savedRequests", "");
9 | pref("extensions.httprequester.contentType.history", "[\"application/json\",\"application/xml\",\"text/plain\",\"application/rdf+xml\",\"text/html\"]");
10 | pref("extensions.httprequester.header.history", "[\"Authorization\",\"Accept\",\"Accept-encoding\",\"Cookie\",\"If-Match\"]" );
11 |
12 | pref("extensions.httprequester.default.protocol", "https");
13 | pref("extensions.httprequester.showAdvancedOptions", false);
14 | pref("extensions.httprequester.prettyPrintResponse", false);
15 | pref("extensions.httprequester.checkFileExtensionForRenderType", true);
16 | pref("extensions.httprequester.renderResponseBrowser", false);
17 | pref("extensions.httprequester.useFastXMLPrettyPrint", true);
18 |
19 | pref("extensions.httprequester.http.methods.custom.write", "[\"PROPFIND\"]");
20 | pref("extensions.httprequester.http.methods.custom.read", "[\"COPY\",\"MOVE\"]");
21 |
--------------------------------------------------------------------------------
/src/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 | {ea4637dc-e014-4c17-9c2c-879322d23268}
8 | HttpRequester
9 | 2.1
10 | 2
11 | A tool for easily making HTTP requests (GET/PUT/POST/DELETE), and keeping a history of transactions.
12 | Tom Mutdosch
13 | Alex Milowski
14 | chrome://httprequester/content/about.xul
15 | chrome://httprequester/skin/httprequester.png
16 | true
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/readme.txt:
--------------------------------------------------------------------------------
1 | HttpRequester is a modified version of the excellent Poster add-on available for Mozilla Firefox.
2 | HttpRequester is distributed under the the BSD License: http://www.opensource.org/licenses/bsd-license.php
3 |
4 | 2.1:
5 | Improved parameter handling:
6 | The parameters list is now automatically populated when viewing requests in the history.
7 | The parameters and URI are now synchronized. Adding/modifying parameters in the list automatically updates the parameters in the URI,
8 | and vice-versa: if you add/modify the parameters directly in the URL they will be reflected in the parameters list.
9 | You can now move parameters up or down in the list, and the URL will automatically reflect the positioning.
10 |
11 | Can now directly edit Header and Parameter names and values in the List. Simply double click to edit the field.
12 |
13 | Multi-select is now supported in the History view for deleting multiple transactions, as well as selecting multiple
14 | transactions to copy-to-clipboard.
15 | Multi-select is also supported in the Headers and Parameters list for deleting/reordering multiple selections
16 | at one time.
17 |
18 | Fixed: PATCH method was not working.
19 | Fixed: couldn't execute custom Methods from the Raw Request dialog
20 | Fixed: Response pane would not update if empty contents were returned for an XML/JSON response.
21 |
22 |
23 | 2.0 (10/7/2014):
24 | Added option to display response in an embedded browser.
25 | This works well in conjunction with the'XML Pretty Viewer' and 'JSON View' addons. The embedded browser will utilize the nicely formatted displays that those addons provide.
26 | Added option to pretty-print JSON and XML responses.
27 | Added resizable sections to allow individually resizing the request and response areas, as well as the Response Headers and History.
28 | Added Authentication button to allow for entering username/password for Basic Authentication. his will ensure that the appropriate Authorization header is sent with the request.
29 | You can also set the timeout value to determine how long to wait before the request times out (Default: 30 seconds)
30 | Added PATCH to the list of HTTP methods
31 | Added tooltip text for request URL list item
32 | Fixed: extra newlines were being being printed for View Raw Transaction causing it to appear double-spaced
33 | Fixed: better styling for section headers
34 |
35 | 1.0.5 (02/02/2014):
36 | Replaced status-bar (addons bar) icon with a toolbar icon. Toolbar icons can be placed anywhere by right-clicking and selecting "Customize..."
37 |
38 |
39 | 1.0.4: (01/23/2012):
40 | 1) Via user request: added ability to add custom methods to the list of
41 | available HTTP methods. Useful for adding things like PATCH (now an Proposed Standard -- RFC 5789).
42 | To add new Methods: enter "about:config" in your URL bar. Then filter on:
43 | extensions.httprequester.http.methods.custom.write
44 | Double-click the value to modify it. You can change it to a list of comma-separated values like:
45 | ["PROPFIND", "PATCH"]
46 | You can also add read-only custom methods too (these methods will not send any entity body) via extensions.httprequester.http.methods.custom.read
47 |
48 | When you bring up HTTP Requester it will show those values in the HTTP method dropdown for use.
49 |
50 |
51 | 1.0.3.1: (09/20/2011):
52 | 1) Fixed: Parameters added to the parameter list were only being added to the request URI for GET requests, and not for POST/PUT/DELETE.
53 | 2) Fixed: Parameters added to the request URI were not added correctly if the URI already had existing URI query.
54 | 3) Fixed: When clicking Parameter Body to move add parameters to the body content, the parameters were still being added to the URI as well.
55 | 4) When viewing raw request, response is now separated with a "-- response --" delimiter to aid in readability.
56 | 5) Fixed: when executing raw request, was including the response content as part of the PUT/POST body
57 |
58 | 1.0.3: (06/05/2011):
59 | 1) Added a "Find..." function in the Content Response area and in the Raw Transaction view window. Press the Find
60 | button or hit CTRL-f to search for text anywhere in the request/response. CTRL-g will do a Find Next to locate the
61 | next instance of the text that was last searched for.
62 |
63 | 1.0.2: (06/02/2011):
64 | 1) Added a column in the transaction history to show Content Length. The value used is the Content-Length response header
65 | if available, and the size of the response body otherwise
66 |
67 | 1.0.1: (05/20/2011):
68 | 1) Added a "View raw transaction" link in the Response area to quickly let you view the entire raw request and response.
69 | This is the same behavior as double-clicking a transaction in the transaction history list.
70 | 2) Cleaned up Content area (made selecting a File to upload a radio button control)
71 | 3) The response content now properly shows with a scrollbar if there are lots of response headers
72 |
73 | 1.0: (05/19/2011):
74 | 1) The transaction list control has been updated; each column is now resizable and re-orderable and can be hidden via the column picker.
75 | The ordering and width of each column are now persisted. Additionally, if a value is too large for a column it will be truncated
76 | and a tooltip will display the full value.
77 | 2) The headers and parameters list controls have been similarly updated.
78 |
79 |
80 | 0.5: (03/07/2011):
81 | 1) Updated to work with Firefox 4
82 | 2) Default to "http://" if no protocol is entered
83 |
84 | 0.4: (02/03/2011)
85 | 1) You can now save and load stored requests.
86 | To save a request, click on a request in the history list and click Save Request. You can optionally give the request a name.
87 | To load a request, click on Load Request - that will bring up a list of all saved requests. You can select any request to load it into your history to view it, or you can click the Execute button to execute it immediately.
88 | 2) Added explicit Delete Request button to remove selected transaction from history list. (You can also hit the Delete key)
89 |
90 | 0.3: (01/19/2011)
91 | 1) History list now shows elapsed time for all requests
92 | 2) Double-clicking a row in the history will show you a raw text version of the request and response
93 | 3) You can now edit raw requests by clicking the Edit Raw Request button; this is useful for making quick tweaks to a previous request, such as adding or changing a header
94 | 4) Paste Request button. You can now copy existing requests from the clipboard (such as a request captured from Live HTTP Headers) by clicking the
95 | Paste Request button, and then executing the request.
96 |
97 | 0.2: (08/01/2010)
98 | 1) Reuse HttpRequester window if already open
99 | 2) Use HttpRequester icon to identify HttpRequester window
100 |
101 | 0.1 adds many improvements (07/27/2010)
102 | 1) requests/responses transactions now take place in a single window. A separate window is not opened for each response.
103 | 2) history of transactions is now recorded (and kept across sessions); can view past requests; re-execute them
104 | 3) HttpRequester opens in a proper window instead of a dialog; can be minimized, maximized
105 | 4) remembers recent URLs, header names, and content types (across sessions)
106 | 5) can copy a request/response to clipboard for pasting into bug report, etc
107 | 6) The UI has been minimialized and cleaned up a bit
108 | 7) Can hit key to close window
109 |
110 | Preferences: via about:config
111 | extensions.httprequester.maxhistory - maximum number of requests to keep
112 | extensions.httprequester.url.maxhistory - maximum number of URLs to keep
113 | extensions.httprequester.contenttype.maxhistory - maximum number of content types to keep
114 | extensions.httprequester.header.maxhistory - maximum number of header names to keep
115 |
116 | extensions.httprequester.history
117 | extensions.httprequester.url.history
118 | extensions.httprequester.contentType.history
119 | extensions.httprequester.header.history
120 |
121 | extensions.httprequester.showAdvancedOptions - set this to true to cause some of the other buttons to appear (Google login, Save/Store/Import default URL/content type, timeout slider)
122 |
123 | If you have any questions/comments/suggestions, shoot me a note.
124 | -Tom Mutdosch
125 |
126 |
127 | --
128 | Usage overview
129 |
130 |
Requests/responses transactions take place in a single application window.
131 |
A history of transactions is recorded (and kept across sessions). You can view past requests, and re-execute them. Selecting a transaction in the History list will show the full request/response.
132 |
For each transaction in the list, the request and response are shown, as well as the Elapsed Time and Content-Length (The value used is the Content-Length response header if available, and the size of the response body otherwise.)
133 |
Each column in the history list is resizable and re-orderable and can be hidden via the column picker. The ordering and width of each column are persisted.
134 |
Double-clicking a row in the history will show you a raw text version of the request and response
135 |
You can edit raw requests by double-clicking a row in the history list, or clicking the Edit Raw Request button. This is useful for easily viewing the request all at once, or for making quick tweaks to a previous request, such as adding or changing headers. This is the same behavior as double-clicking a transaction in the transaction history list.
136 |
You can press the Delete Request button to remove a selected transaction from history list. (You can also hit the Delete key)
137 |
Recent URLs, header names, and content types are remembered across sessions, and can easily be selected from drop-down lists.
138 |
You can copy a request/response to clipboard for pasting into bug report, etc. You can also copy existing requests from the clipboard by clicking the Paste Request button, and then executing the request.
139 |
Press the key to close the HttpRequester window
140 |
Save and load stored requests: To save a request, click on a request in the history list and click Save Request. You can optionally give the request a name.
141 |
To load a request, click on Load Request - that will bring up a list of all saved requests. You can select any request to load it into your history to view it, or you can click the Execute button to execute it immediately.
142 |
143 | Advanced Preferences (via about:config):
144 | extensions.httprequester.maxhistory - maximum number of requests to keep
145 | extensions.httprequester.url.maxhistory - maximum number of URLs to keep
146 | extensions.httprequester.contenttype.maxhistory - maximum number of content types to keep
147 | extensions.httprequester.header.maxhistory - maximum number of header names to keep
148 | extensions.httprequester.showAdvancedOptions - set this to true to cause some of the other buttons to appear (Google login, Save/Store/Import default URL/content type, timeout slider)
149 |
150 |
151 | If you have any questions/comments/suggestions, shoot me a note.
--------------------------------------------------------------------------------
/src/skin/default.css:
--------------------------------------------------------------------------------
1 | #httprequester-window {
2 | min-width: 450px;
3 | width: 1200px;
4 | height: 768px;
5 | overflow: auto;
6 | }
7 |
8 | caption {
9 | font-weight: bold;
10 | font-variant: small-caps;
11 | }
12 |
13 | #statusHeading {
14 | font-weight: bold;
15 | }
16 |
17 | /* set tooltip max-width to none so that it does not crop when it gets too large */
18 | #httprequesterTooltip {
19 | max-width: none;
20 | }
21 |
22 | #httprequesterSidebar {
23 | overflow: scroll;
24 | }
25 |
26 | #sidebar {
27 | max-width: none !important;
28 | }
29 |
30 | page,window,dialog {
31 | font-size: 80%;
32 | font-family: Arial, Helvetica, Sans-Serif;
33 | }
34 |
35 | row {
36 | -moz-box-align: center;
37 | }
38 |
39 |
40 | p.label {
41 | margin: 0pt;
42 | padding: 2pt;
43 | font-weight: bold;
44 | }
45 |
46 | /* ensure that the request section (and request Url box) are a minimum width at startup */
47 | #requestbox {
48 | width: 400px;
49 | }
50 | #response {
51 | min-width: 500px;
52 | min-height: 500px;
53 | }
54 |
55 | #response #content {
56 | font-family: monospace;
57 | font-size: 110%;
58 | min-width: 400px;
59 | min-height: 300px;
60 | }
61 |
62 | .small-buttons1 button {
63 | font-size: 75%;
64 | }
65 |
66 | .medium-buttons button {
67 | padding: 0pt;
68 | }
69 |
70 | #about {
71 | min-height: 250px;
72 | min-width: 300px;
73 | width: 300px;
74 | }
75 |
76 | #response #title {
77 | padding: 0.2em;
78 | padding-left: 0.5em;
79 | }
80 |
81 | /* set background browser to white; by default it is ugly gray */
82 | #browserIframe {
83 | background-color: white;
84 | }
--------------------------------------------------------------------------------
/src/skin/httprequester.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tommut/HttpRequester/d62a6ea6f32406ab44d494458e652c189d2d5fe0/src/skin/httprequester.png
--------------------------------------------------------------------------------
/src/skin/httprequester16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tommut/HttpRequester/d62a6ea6f32406ab44d494458e652c189d2d5fe0/src/skin/httprequester16x16.png
--------------------------------------------------------------------------------
/src/skin/overlay.css:
--------------------------------------------------------------------------------
1 | /* This is just an example. You shouldn't do this. */
2 | #httprequester-status-bar {
3 | padding: 0px;
4 | margin: 0px;
5 | }
6 |
7 | #httprequester-status-bar toolbarbutton {
8 | padding: 0px;
9 | margin: 0px;
10 | }
--------------------------------------------------------------------------------