I'm working on a web application where I need to access elements of an iFrame using JavaScript. To do that, the iFrame has to send an "Allow-Control-Allow-Origin: *" header to the browser.
Unfortunately this doesn't happen, that's why I'm using an extension to modify the response headers, but for some reason, setResponseHeader doesn't work.
It gets even more confusing since I'm using setResponseHeader to strip X-Frame-Options, but when I'm setting a custom header, it just won't work.
I'm using Firefox's "Inspect Element"'s Network tab to observe the requests, and while it shows the request header being set correctly, it doesn't show the response header.
That's how I'm setting the request and response headers.
var chrome = require("chrome");
chrome.Cc["#mozilla.org/observer-service;1"].getService( chrome.Ci.nsIObserverService ).addObserver({
observe : function(subject, topic, data) {
var channel = subject.QueryInterface( chrome.Ci.nsIHttpChannel );
channel.setRequestHeader("x-mysite-extended", "somedata", false);
}
},"http-on-modify-request",false);
chrome.Cc["#mozilla.org/observer-service;1"].getService( chrome.Ci.nsIObserverService ).addObserver({
observe : function(subject, topic, data) {
var channel = subject.QueryInterface( chrome.Ci.nsIHttpChannel );
channel.setResponseHeader("x-mysite-extended", "somedata", false);
}
},"http-on-examine-response",false);
Again, the request header works according to the Network tab. I tried http-on-modify-request to set the response header but that didn't work as well.
That's how I'm stripping of the X-Frame-Options header, which works.
let myListener =
{
observe : function (aSubject, aTopic, aData)
{
console.log(aTopic);
if (aTopic == "http-on-examine-response")
{
let channel = aSubject.QueryInterface(Ci.nsIHttpChannel);
try
{ // getResponseHeader will throw if the header isn't set
let hasXFO = channel.getResponseHeader('X-Frame-Options');
if (hasXFO)
{
// Header found, disable it
channel.setResponseHeader('X-Frame-Options', '', false);
}
}
catch (e) {}
}
}
}
var observerService = Cc["#mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
observerService.addObserver(myListener, "http-on-examine-response", false);
I've been trying to solve this for two hours now so any help is appreciated. Thanks.
You're adding obserer for http-on-examine-response, with this you can only getResponseHeader
change it to http-on-modify-request. then you can setRequestHeader, you cant getResponseHeader in on modify request though.
This is scrap code but it worked for me:
observe : function(aSubject, aTopic, aData) {
// Make sure it is our connection first.
if (aSubject == channel) {
//this is our channel
//alert('is my mine');
cdxFire.myChannel = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
if (cdxFire.myChannel.requestMethod == 'GET') {
//alert('its a get so need to removeObserver now');
//cdxFire.observerService.removeObserver(modHeaderListener, "http-on-modify-request");
}
if (aTopic == 'http-on-modify-request' && cdxFire.myChannel.requestMethod == 'POST') {
//can set headers here including cookie
try {
var xContentLength = httpChannel.getRequestHeader('Content-Length');
var xContentType = httpChannel.getRequestHeader('Content-Type');
//alert('content length is there so change it up');
cdxFire.myChannel.setRequestHeader('Content-Type','',false);
cdxFire.myChannel.setRequestHeader('Content-Type',xContentType,false);
cdxFire.myChannel.setRequestHeader('Content-Length','',false);
cdxFire.myChannel.setRequestHeader('Content-Length',xContentLength,false);
Related
.Net Version 4.5.2
When loading a page that returns 302, the browser control does load the redirected URL, presumably correctly. When you examine the call results in Fiddler, the entire correct page is returned from the server.
Now, the page never 'Completes' for a long time, but does go into an 'Interactive' state where you should be able to interact with it, no?
When I look at the WebBrowser's Document, which is not null, it has no content, so you can't access Body, or any element.
The results is encoded - gzip. You have to Decode it in Fiddler to see it.
How do I get the returned HTML to be available in the Document property?
using (browser = new WebBrowser()) {
browser.ClientSize = new Size(800, 600);
browser.ScrollBarsEnabled = false;
browser.ScriptErrorsSuppressed = true;
System.Windows.Forms.HtmlDocument doc = null;
browser.Navigate(_url);
// Wait for control to load page
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
if (browser.ReadyState == WebBrowserReadyState.Interactive && browser.Document != null)
{
// give some redering time..
Thread.CurrentThread.Join(500);
Application.DoEvents();
doc = browser.Document;
break;
}
}
var elements = browser.Document.GetElementsByTagName("INPUT");
foreach (HtmlElement element in elements)
{
if (element.Name.ToLower().Contains("theInputFieldName"))
{
element.InnerText = NewFieldContentsVariable;
}
//to get the text use : string value = element.GetAttribute("value");
//to set the text use : elemet.InnerText = "something";
}
...
This is my code. It works in Firefox and Chrome but not Safari. I get no errors.
<script>
var cleanData = new FormData();
cleanData.append("test", "test");
alert(cleanData.get("test"));
</script>
Does anyone know a workaround?
Apparently, Safari has no means of getting values stored in FormData objects at this time. There is no workaround at this time, and apparently it's not practical to polyfill.
Sorry :(
Notes:
https://developer.mozilla.org/en-US/docs/Web/API/FormData/get#Browser_compatibility
https://www.bountysource.com/issues/27573236-is-it-possible-to-polyfill-missing-formdata-methods
I solved this by conditionally (if Safari is the browser) iterating through the elements property of an actual form. For all other browser, my wrapper just iterates through FormData entries(). The end result of my function, in either case, is a simple javascript object (JSON) which amounts to name/value pairs.
function FormDataNameValuePairs(FormName)
{
var FormDaytaObject={};
var FormElement=$('#'+FormName).get(0);
if (IsSafariBrowser())
{
var FormElementCollection=FormElement.elements;
//console.log('namedItem='+FormElementCollection.namedItem('KEY'));
var JQEle,EleType;
for (ele=0; (ele < FormElementCollection.length); ele++)
{
JQEle=$(FormElementCollection.item(ele));
EleType=JQEle.attr('type');
// https://github.com/jimmywarting/FormData/blob/master/FormData.js
if ((! JQEle.attr('name')) ||
(((EleType == 'checkbox') || (EleType == 'radio')) &&
(! JQEle.prop('checked'))))
continue;
FormDaytaObject[JQEle.attr('name')]=JQEle.val();
}
}
else
{
var FormDayta=new FormData(FormElement);
for (var fld of FormDayta.entries())
FormDaytaObject[fld[0]]=fld[1];
}
return FormDaytaObject;
}
where IsSafariBrowser() is implemented by whatever your favorite method is, but I chose this:
function IsSafariBrowser()
{
var VendorName=window.navigator.vendor;
return ((VendorName.indexOf('Apple') > -1) &&
(window.navigator.userAgent.indexOf('Safari') > -1));
}
Example usage in OP's case, assuming that you have an actual form called CleanDataForm instead of creating a FormData from scratch:
var cleanData=FormDataNameValuePairs('CleanDataForm');
alert(cleanData.test);
I've got the following code in one of my views
#if (ViewBag.LoginInfo != null)
{
var loginToken = "#ViewBag.LoginInfo.Token";
var loginUser = "#ViewBag.LoginInfo.UserNameJs";
var notifyUrl = "#ViewBag.LoginInfo.NotificationUrl";
}
The code between { } should be rendered to the page as javascript, however it seems to be getting run as serverside code. I'm aware razor switches back to client code when it sees html in this case the code is valid as C# and javascript. How to I force everthing between { } to be written to the page as javasript?
Thanks
Alternatively use #:
#if (ViewBag.LoginInfo != null)
{
#:var loginToken = #Html.Raw(Json.Encode(ViewBag.LoginInfo.Token);
#:var loginUser = #Html.Raw(Json.Encode(ViewBag.LoginInfo.UserNameJs);
#:var notifyUrl = #Html.Raw(Json.Encode(ViewBag.LoginInfo.NotificationUrl);
}
You could wrap them in <text> tags:
#if (ViewBag.LoginInfo != null)
{
<text>
var loginToken = #Html.Raw(Json.Encode(ViewBag.LoginInfo.Token);
var loginUser = #Html.Raw(Json.Encode(ViewBag.LoginInfo.UserNameJs);
var notifyUrl = #Html.Raw(Json.Encode(ViewBag.LoginInfo.NotificationUrl);
</text>
}
Also notice how I have safely encoded the values. Your example will produce invalid javascript if for example your token contains the " character. You should never be mixing javascript and server side values without using a safe serializer as shown in my example.
I am using Google Place Api where is on some results "photo_reference" (similar to "reference") value. I cannot find any mention about that how to use it to get that photo. I know how to use "reference" to get PlaceDetail and I am sure that usage of photo_reference will be similar, but I cannot find JSON/XML URL for this photo_reference request. Thank you for any help. Pavel
Please take a look at documentation here: https://developers.google.com/places/documentation/photos
They've just announced this new Place Photos feature
In short this is how you should use this new feature:
https://maps.googleapis.com/maps/api/place/photo?photoreference=PHOTO_REFERENCE&sensor=false&maxheight=MAX_HEIGHT&maxwidth=MAX_WIDTH&key=YOUR_API_KEY
just substitute your own values in place of:
PHOTO_REFERENCE
MAX_HEIGHT - int value from 1 to 1600
MAX_WIDTH - int value from 1 to 1600
YOUR_API_KEY
and you are done
The Places API now supports the return of one place photo if available for a Place Search request and up to ten place photos for a Place Details request.
If a photos array is returned with your request, you can pass the photo_reference from a contained photo object to a Place Photo request with the maxheight and/or maxwidth, sensor and key parameters:
https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=CnRvAAAAwMpdHeWlXl-lH0vp7lez4znKPIWSWvgvZFISdKx45AwJVP1Qp37YOrH7sqHMJ8C-vBDC546decipPHchJhHZL94RcTUfPa1jWzo-rSHaTlbNtjh-N68RkcToUCuY9v2HNpo5mziqkir37WU8FJEqVBIQ4k938TI3e7bf8xq-uwDZcxoUbO_ZJzPxremiQurAYzCTwRhE_V0&sensor=false&key=AddYourOwnKeyHere
Please see the documentation for more details.
please bear in mind that there are no free photo requests anymore.
At this moment (November 2020), it is $7.0 for 1000 requests (if your volume is up to 100,000). Check the photo below.
Read more on Google Places billing info page.
Step 1: The URL you should use to call Google Place Photos is :
String url = https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=PHOTOREF&key=YOUR_API_KEY
Refer: https://developers.google.com/places/web-service/photos
Step 2: Since the above URL redirects to another URL, use HTTPClient, as it automatically handles redirect stuff.
Code:
DefaultHttpClient hc = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
HttpContext context = new BasicHttpContext();
hc.setRedirectHandler(new DefaultRedirectHandler() {
#Override
public URI getLocationURI(HttpResponse response,
HttpContext context) throws org.apache.http.ProtocolException {
//Capture the Location header here - This is your redirected URL
System.out.println(Arrays.toString(response.getHeaders("Location")));
return super.getLocationURI(response,context);
}
});
// Response contains the image you want. If you test the redirect URL in a browser or REST CLIENT you can see it's data
HttpResponse response = hc.execute(httpget, context);
if(response.getStatusLine().getStatusCode() == 200) {
// Todo: use the Image response
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
Bitmap bmp = BitmapFactory.decodeStream(instream);
ImageView imageView = new ImageView(context);
imageView.setImageBitmap(bmp);
images.add(imageView);
instream.close();
}
}
else {
System.out.println(response.getStatusLine().getStatusCode()+"");
}
Hope this helps everyone.
After initiating map you can get place details with it's images
const service = new window.google.maps.places.PlacesService(map);
service.getDetails(
{
placeId: "some_place_id_here"
},
(data, status) => {
if (status === window.google.maps.places.PlacesServiceStatus.OK) {
data.photos &&
data.photos.forEach(photo => {
console.log(photo.getUrl({ maxWidth: 500, maxHeight: 500 }));
});
}
}
);
Solving the PhotoReference issue for Javascript
User #R.K solved this issue in java, however in js you need to use fetch(). Here's the code I used:
await fetch(proxyUrl+url).then(async(ref)=>{
await ref.blob()}).then((image)=>{
// do what you need to do
console.log(image)
}).catch((err)=>{
console.log(err);
})
In this, I used a heroku link for the proxyUrl and the url shown in #Chriss Green's post for url. Hope this helps anyone confused using js!
I need analog of Chrome chrome.tabs.update or Firefox loadURI in Safari.
I've tried safari.application.activeBrowserWindow.activeTab.url = newURL but it doesn't work with bookmarklets urls like javascript:...
That's right, it doesn't work. You're going to have to pass a message to an injected script in a web page to open the bookmarklet. For example:
in the global page's script:
var activeTab = safari.application.activeBrowerWindow.activeTab;
var url = "javascript:alert('hello sucker')";
activeTab.page.dispatchMessage("pleaseLoadThisUrl", url);
in the injected script:
safari.self.addEventListener("message", handleMessage, false);
function handleMessage(e) {
if (e.name == "pleaseLoadThisUrl") {
window.location = e.message;
}
}
That will work.