Xulrunner Browser Posting data via loadURI() - firefox-addon

I have XULrunner opening a browser window that loads a XUL page from my local server. I am trying to post some data back to my PHP but with little success. I am just using the example at https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Post_data_to_window
Here's what my javascript looks like
var params = obj.getAttribute('params');
var url = obj.getAttribute('url');
alert(params + ' - ' + url);
const Cc = Components.classes;
const Ci = Components.interfaces;
var stringStream = Cc['#mozilla.org/io/string-input-stream;1'].createInstance(Ci.nsIStringInputStream);
stringStream.data = params;
var postdata = Cc['#mozilla.org/network/mime-input-stream;1'].createInstance(Ci.nsIMIMEInputStream);
postdata.addHeader('Content-Type', 'application/x-www-form-urlencoded');
postdata.addContentLength = true;
postdata.setData(stringStream);
document.getElementById('mainbrowser').loadURI(url, null, postdata, null);
Without trying to confuse the matter too much, this is obviously part of a much bigger picture. The only part not shown, that is relevant, is where obj is derived. Basically it is a temporary XUL element that has all the parameters stored in it for easy access as I pass them around to different functions in my javascript. Also the params is in the format of name1=data1&name2=data2.
I know it is working up to the alert as it does outputs the parameters that I am sending. I am also sure the browser is being reloaded as the data I entered in the form is being cleared each time I submit it. But in my PHP if I output the contents of $_POST there is nothing.
I did have this working using XMLHttpRequest but it wasn't ideal for how I needed things to work. So I am hoping to get his method working.

Related

Data Gets Converted when passed to CREATE_STREAM

I have created an UI5 Application to read a file and send it to a custom OData Service in the Backend.
onUploadFile: function() {
var oFileUpload =
this.getView().byId("fileUploaderFS");
var domRef = oFileUpload.getFocusDomRef();
var file = domRef.files[0];
var that = this;
var reader = new FileReader();
var ftype = file.type;
reader.readAsArrayBuffer(file);
reader.onload = function(evt) {
var vContent = evt.currentTarget.result
console.log(vContent);
var hex = that.buf2hex(vContent);
that.updateFile(hex, ftype);
}
},
buf2hex: function(buffer) {
return [...new Uint8Array(buffer)]
.map(x => x.toString(16).padStart(2, '0'))
.join('');
}
When I print the content of hex on the console before sending it to the backend, the data starts with 89504e470d0a1a0a0000000d49484 ....
Even before sending the data in the payload to Odata Service it shows the correct data
Here is the Odata Service
Inside the Create Stream the data when received, is getting converted into something else. As a result the image that has been saved is not opening.
I tried to change the Data Type of Content in SEGW to Binary and it did not work. I also tried to convert the data in the create_stream but in vain. At last I tried reading the data in UI5 in different formats but of no use.
This whole Odata service works perfectly fine when I load the data through Postman Application.
Please help me resolve this Issue. Thanks In Advance.
The sap.ui.unified.FileUploader has everything built in. No need for conversions from Buffer to hex.
Make sure that your FileUploader knows where to upload the file
<unified:FileUploader xmlns:unified="sap.ui.unified"
id="fileUploaderFS"
uploadUrl="/sap/opu/odata/sap/Z_TEST_SRV/FileSet"
/>
The attribute uploadUrl points to the media entity for which you implemented the create_stream method.
Then when the upload is triggered via button press, simply get the FileUploader, set the token (for security reasons when doing a POST request), and fire the upload method.
onUploadFile: function () {
const oFileUpload = this.getView().byId("fileUploaderFS");
const sToken = this.getModel("nameOfTheModel").getSecurityToken();
const oTokenParam = new FileUploaderParameter({
name: "x-csrf-token",
value: sToken
});
oFileUpload.removeAllHeaderParameters()
oFileUpload.addHeaderParameter(oTokenParam);
oFileUpload.upload();
}
To use FileUploaderParameter, make sure to import it at the beginning:
sap.ui.define([
// ...,
"sap/ui/unified/FileUploaderParameter"
], function (/*..., */FileUploaderParameter) {
// ...
Now about your File entity. When working with it via create_stream or read_stream, you don't use the entity structure but is_media_resource. This means your entity doesn't need a property content. Or most of the other properties (except a unique id and the mime type). All other properties would only be used if you want to do one of the CRUD methods (which happens almost never when dealing with streams).

window.location in Firefox and Chrome giving me two different returned strings for a Google Macro

My application is using Google Apps Script HTML Service. The URL for Apps Script looks like this:
https://script.google.com/macros/s/AKfycby2Zr2apAai2sIW6eiWTc8yNakGg5M9oLQkmhcz-IRqs22qoJhm/exec
In Firefox, this line of code:
window.daURL = window.location;
returns this:
https://script.google.com/macros/blank
Firefox puts in the word blank. Chrome gives me the entire URL.
What I've been doing, is getting the entire URL, then using Javascript string methods to parse the URL for whatever info I need to check for a Facebook login. The Facebook login appends info to the end of the URL beginning with a hash tag. If the hash tag is there, the code checks for and validates a Facebook login.
I need either the entire URL, or to be able to get an appended string after the /exec.
Chrome gives me the entire URL with window.location, but Firefox will not.
If I try:
window.daURL = window.location.pathname;
Firefox returns:
/macros/blank
If I try:
window.daURL = window.location.search;
I get nothing returned, even when a string is appended to the URL.
I can get a string appended to the URL with the Apps Scripts doGet(e) function:
e.parameter.theNameOfTheStringArg
E.g. www.URL.com?myArg=Something
Use: var getString = e.parameter.myArg
But I can't get a hashed appended value to the URL with doGet(e). I need to check for a hash in the URL.
I figured out that I can use window.location.href to check for the existence of the hash tag appended to the url. So I use window.onload to check for a hashtag in the url, and doGet(e) to check for string attachments to the URL. I need to run both.
<script>
//Script tag in first HTML file that always loads
window.onload=function(){
console.log("This onload did run");
//get the URL out of the browsers address bar
//the URL can have multiple different strings attached depending upon the situation.
//Any situation other than something with a hashtag is initiated in the back end.
window.daURLhash = window.location.hash;
console.log('daURLhash: ' + daURLhash);
window.urlHash = daURLhash.toString();
console.log('urlHash: ' + urlHash);
console.log("url: " + urlHash);
//If a certain situation, there will be a hashtag in the url string
if (urlHash != undefined && urlHash != null) {
if (urlHash.length > 0) {
window.hashExist = true;
console.log('hashExist: ' + hashExist);
};
};
if (window.hashExist === true) {
code here
</script>

History.js PushState in html 4 browser (IE) changes the url incorrectly

Im usnig History.js to push a url but in IE it appends the page name.
if my original url is :
http://www.mydomain.com/Home.aspx
and then I execute the following:
var url = window.location.protocol + '//' + window.location.host + '/Home.aspx?id=2&pl=4';
History.pushState(null, null, url)
In Chrome my url becomes : http://www.mydomain.com/Home.aspx?id=2&pl=4
In IE 8 my url becomes: http://www.mydomain.com/Home.aspx#Home.aspx?id=2&pl=4
If I paste the IE 8 url in chrom my code fails...
Firstly, what should the correct html 4 url look like and secondly, how do I fix it?
I believe you are not pushing a state properly, try reformatting the url you push e.g. History.pushState({data: 'home'}, null, '/Home/').
Or maybe you thought that pushing a state also sends a request to server like you did there with a query? It does not buddy.
Therefore, dont expect anything to work by pasting the state u pushed into other browsers. First, because other browsers have no history about your site and secondly you need to catch the statechange event with History.
e.g.
History.Adapter.bind(window, 'statechange',
function() {
if (History.getState().data.page === 'home') {
//do what u would like with current state
}
);

WebRequest/POST question on extracting specific data from a website

I am trying to gather data on specific events from a company website: http://pipeline.kindermorgan.com/infoposting/notices.aspx?type=CRIT
I have worked a lot of similar websites but so far they have been pretty simple and it’s just a matter of going to the website and working with the response stream. In this case the website requires you to select a value from the first combo box (TSP/TSP Name). Without any info being passed, the URL will return the data associated with the first item in the list. I really need to be able to get the data associated with any of the items in the list.
Here is the code I have been using thus far but it fails with a Server Error 500 so I am guessing that either I did not form the POST properly or am missing some data in the post data):
For the page I have listed above I just want to get a response stream with the table of the notices for a particular TSP from the combo box (starting with Trailblazer). I know the control is “ctl00$ContentPlaceHolder1$ddlpipeline” and the value I want to send is 24. When I navigate via IE, I also have to press the “Retrieve” button.
When I look at the POST request using FireBug, I notice that there are a lot of other target/values included. I’m not sure if I need to send all of those as well and (having never done a POST before) I am not sure how to format the data in the POST to do that.
Bear with me if this request seems odd. I am more of a database person and am looking to automate a lot of the stuff we are required to look at manually every day. Any help would be greatly appreciated!
var encoding = new ASCIIEncoding();
var postData = "ctl00$ContentPlaceHolder1$ddlpipeline=24";
byte[] data = encoding.GetBytes(postData);
string RemoteURI = "http://pipeline.kindermorgan.com/infoposting/notices.aspx?type=CRIT";
var myRequest = (HttpWebRequest)WebRequest.Create(RemoteURI);
myRequest.Method = "POST";
myRequest.ContentType = "application/x-www-form-urlencoded";
myRequest.ContentLength = data.Length;
var newStream = myRequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
var response = myRequest.GetResponse();
var responseStream = response.GetResponseStream();
var responseReader = new StreamReader(responseStream);
I actually resolved the issue and there were a number of things I found out in the process that I will share for the benefit of others who may look at this thread.
First, I had to build the POST data exactly as it appears in the POST in a browser (I used Firebug to see the POST data). This meant getting the hidden arguments as well (particularly VIEWSTATE and EVENTVALIDATION). I was able to get these by just downloading the default page source for the page (by the way, i do this in the code because it is not static for this site) and parsing out the values for the hidden fields. I then build the POST data string with any changes I may have (in my case changing the date was important but in the future I may change other things).
Now the thing that really had me stumped. I confirmed that the POST data string was exactly the same as the one sent by FireFox/FireBug through a character by character comparison and it still wouldn't work. I then remembered in a previous scraping case that I had to set the user agent.
So here is the code I ended up with:
string postData = String.Format("__EVENTTARGET=&__EVENTARGUMENT=&__LASTFOCUS="
+ "&__VIEWSTATE={0}"
+ "&ctl00%24UltraWebTree1={1}"
+ "&ctl00%24ContentPlaceHolder1%24ddlNoticeCategory={2}"
+ "&ctl00%24ContentPlaceHolder1%24ddlpipeline={3}"
+ "&ctl00%24ContentPlaceHolder1%24Button1={4}"
+ "&ctl00%24ContentPlaceHolder1%24tbDate={5}"
+ "&ctl00%24ContentPlaceHolder1%24ddlNoticeType={6}"
+ "&ctl00%24ContentPlaceHolder1%24tbSubject={7}"
+ "&ctl00%24ContentPlaceHolder1%24ddlNoticeSubType={8}"
+ "&ctl00%24ContentPlaceHolder1%24ddlOrderBy={9}"
+ "&ctl00%24ContentPlaceHolder1%24hfmode={10}"
+ "&ctl00%24ContentPlaceHolder1%24hfODSCommand={11}&ctl00%24hfPipeline={12}"
+ "&__PREVIOUSPAGE={13}&__EVENTVALIDATION={14}",
viewstate, webtree, noticecategory, pplcode,
button1, todaydate, noticetype, subject,
noticesubtype, orderby, hfmode, hfODSCommand,
hfPipeline, previouspage, eventvalidation);
var encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(postData);
var myRequest = (HttpWebRequest)WebRequest.Create(RemoteURI);
myRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" ;
myRequest.Method = "POST" ;
myRequest.ContentType = "application/x-www-form-urlencoded";
myRequest.ContentLength = data.Length;
var newStream = myRequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
var myresponse = myRequest.GetResponse();
var responseStream = myresponse.GetResponseStream();
var responseReader = new StreamReader(responseStream);
string webpagesource = responseReader.ReadToEnd();
Hope this helps someone else.

Modify URL before loading page in firefox

I want to prefix URLs which match my patterns. When I open a new tab in Firefox and enter a matching URL the page should not be loaded normally, the URL should first be modified and then loading the page should start.
Is it possible to modify an URL through a Mozilla Firefox Addon before the page starts loading?
Browsing the HTTPS Everywhere add-on suggests the following steps:
Register an observer for the "http-on-modify-request" observer topic with nsIObserverService
Proceed if the subject of your observer notification is an instance of nsIHttpChannel and subject.URI.spec (the URL) matches your criteria
Create a new nsIStandardURL
Create a new nsIHttpChannel
Replace the old channel with the new. The code for doing this in HTTPS Everywhere is quite dense and probably much more than you need. I'd suggest starting with chrome/content/IOUtils.js.
Note that you should register a single "http-on-modify-request" observer for your entire application, which means you should put it in an XPCOM component (see HTTPS Everywhere for an example).
The following articles do not solve your problem directly, but they do contain a lot of sample code that you might find helpful:
https://developer.mozilla.org/en/Setting_HTTP_request_headers
https://developer.mozilla.org/en/XUL_School/Intercepting_Page_Loads
Thanks to Iwburk, I have been able to do this.
We can do this my overriding the nsiHttpChannel with a new one, doing this is slightly complicated but luckily the add-on https-everywhere implements this to force a https connection.
https-everywhere's source code is available here
Most of the code needed for this is in the files
IO Util.js
ChannelReplacement.js
We can work with the above files alone provided we have the basic variables like Cc,Ci set up and the function xpcom_generateQI defined.
var httpRequestObserver =
{
observe: function(subject, topic, data) {
if (topic == "http-on-modify-request") {
var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
var requestURL = subject.URI.spec;
if(isToBeReplaced(requestURL)) {
var newURL = getURL(requestURL);
ChannelReplacement.runWhenPending(subject, function() {
var cr = new ChannelReplacement(subject, ch);
cr.replace(true,null);
cr.open();
});
}
}
},
get observerService() {
return Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
},
register: function() {
this.observerService.addObserver(this, "http-on-modify-request", false);
},
unregister: function() {
this.observerService.removeObserver(this, "http-on-modify-request");
}
};
httpRequestObserver.register();
The code will replace the request not redirect.
While I have tested the above code well enough, I am not sure about its implementation. As far I can make out, it copies all the attributes of the requested channel and sets them to the channel to be overridden. After which somehow the output requested by original request is supplied using the new channel.
P.S. I had seen a SO post in which this approach was suggested.
You could listen for the page load event or maybe the DOMContentLoaded event instead. Or you can make an nsIURIContentListener but that's probably more complicated.
Is it possible to modify an URL through a Mozilla Firefox Addon before the page starts loading?
YES it is possible.
Use page-mod of the Addon-SDK by setting contentScriptWhen: "start"
Then after completely preventing the document from getting parsed you can either
fetch a different document from the same domain and inject it in the page.
after some document.URL processing do a location.replace() call
Here is an example of doing 1. https://stackoverflow.com/a/36097573/6085033

Resources