XMLHttpRequest How to know what setRequestHeader to send? - javascript

I just started using MSXML2.XMLHTTP object with VBA and I'm trying to interact with our Content Server (create, move, copy, delete files).
I found some random working code on the internet but I still do not fully understand what is going on.
Set req As New MSXML2.XMLHTTP
req.Open "MKCOL", "https://company/dav/nodes/" & URIsource & "/" & Encoded_FolderName, False
req.SetRequestHeader "Content-Type", "text/xml"
req.Send
URIsource is an objID from the server (ie : 12345678)
Encoded_Foldername is the folder name passed into this a function called URLEncode found here
From the OpenText website I tought I was supposed to put :
req.SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
But it doesn't work with my code. I must use the previous one.
I also have a function to copy a file and it uses :
req.setRequestHeader "Destination", strDestURL
How am I supposed to know what Requestheader to use? Is there a list somewhere for post, put, get, etc. ? I understood that "Content-Type" is used to make sure the server understands the request but that's it.
Thank you

Request headers contain information about the sender, body of the request and required response.
http://help.dottoro.com/ljhcrlbv.php

Related

Django Ajax communication, Django doesn't recognize as being Ajax (using request.is_ajax() )

I'm using Ajax with Django. The data is transmitted further but is not recognize as being Ajax. Browser Chrome/Firefox;
To check if the request is done trough ajax, I use:
`request.is_ajax()` method, but this fails, not true, so I checked this method how is working and:
def is_ajax(self):
return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
I verified META.get('HTTP_X_REQUESTED_WITH') and I get None;
I'm think is something with ContentType or I need to set another header. But How ?. My JavaScript is set this way :
xhr.open('post', event.target.action, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest");
xhr.send(data));
At a further check seems request.Meta doesn't contain Content-type also.
From the official documentation:
With the exception of CONTENT_LENGTH and CONTENT_TYPE, as given above, any HTTP headers in the request are converted to META keys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP_ prefix to the name. So, for example, a header called X-Bender would be mapped to the META key HTTP_X_BENDER.
So the name of the header should be X-Requested-With:
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");

Fetch API with NO-CORS redirect - can't get any Response Headers

I have gone over a dozen pages, explanations, questions here, and I am kinda getting frustrated. Noone talks of this situation directly.. So here's what I have... My torrent tracker http://www.tribalmixes.com/ has a script that scans my radio https://www.tm-radio.com/ for new episodes that aired today and shares those as torrents. this game has been happening since 2006. The script checks response headers of some pages and decides whether to download as mp3 or skip in case of the html response.
So recently i've switched radio to https and now there's a 301 redirect in the chain of request-response. I understand there are other solutions to this, but i decided to try fetch API first.. Back in 2006-2007 i was really proud to have remade my torrent tracker with AJAX, only thanks to that lost proper search engine indexing and bunch of users didn;t like it.. Anyways, now am trying to use fresh new technologies on the remade radio site. And since AJAX is not that fancy anymore, going with Fetch API. so once again, I am trying to replace AJAX with FETCH on an already existing mechanism without remaking the mechanism.
But sites are obviously different, so I have to do NO-CORS request, since script is on tribalmixes.com. although sites are on same server. so of course simple folder check can work, but trying to look into the future when sites are separated. Another solutions would be to run a simple ajax request to a local php script that would CURL the URL and return the headers. But why not Fetch? =)
so here's what I have so far for JS
var myHeaders = new Headers();
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'no-cors',
redirect: 'follow',
cache: 'default' };
fetch(turl, myInit).then(function(response) {
const rtype = response.headers.get("Content-Type");
console.log(rtype);
for (var pair of response.headers.entries()) {
console.log(pair[0]+ ': '+ pair[1]);
}
return (response);
}).then(function(text) {
console.log(text);
});
//for obvious reasons i am not posting the url..
the response I am getting is there but pretty much empty. No error. But for some reason "redirected" says "false"... i thought opaque only shows when NO-CORS redirect happens, no?
Response {type: "opaque", url: "", redirected: false, status: 0, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers
__proto__: Headers
ok: false
redirected: false
status: 0
statusText: ""
type: "opaque"
url: ""
__proto__: Response
}
So my question is: am I correct to assume that this is the right way to do it, and that this is undoable this way? Can or can not Fetch API deliver response headers on an opaque response. TBH all i get is that - response is opaque. everything else is empty... Everyone says they get at least something, but i just want 1 none-guarded header Content Type, and cannot get it no matter what i do... Is it NOT possible at the moment? this was all working towards an awesome mp3 converter like keepvid.. but never went past the development stage,,
And before I go ahead and add other headers to radio server response, all i want is to see 1 simple header..
Please, help! losing my mind over here...

Navigator.sendBeacon() to pass header information

I am using navigator for communicating with the server , but problem is that we need to pass some header information as there is filter which recognise the request is from the valid source.
Can anybody help on this?
Thanks.
See the Navigator.sendBeacon MDN documentation for further information.
Create a blob to provide headers. Here is an example:
window.onunload = () => {
const body = {
id,
email,
};
const headers = {
type: 'application/json',
};
const blob = new Blob([JSON.stringify(body)], headers);
navigator.sendBeacon('url', blob);
};
navigator.sendBeacon will send a POST request with the Content-Type request header set to whatever is in headers.type. This seems to be the only header you can set in a beacon though, per W3C:
The sendBeacon method does not provide ability to customize the request method, provide custom request headers, or change other processing properties of the request and response. Applications that require non-default settings for such requests should use the [FETCH] API with keepalive flag set to true.
I was able to observe some of how this worked through this Chromium bug report.
As written in the Processing Model of sendBeacon :
Extract object's byte stream (transmittedData) and content type (contentType).
How extraction is performed is described here
What I've gathered is that the content type of the transmitted data is extracted, and it is set as the Content-Type of the HTTP request.
1) If a Blob object is sent, the Content-Type becomes the Blob's type.
2) If a FormData object is sent, the Content-Type becomes multipart/form-data
3) If a URLSearchParams object is sent, the Content-Type becomes application/x-www-form-urlencoded
4) If a normal string is sent, the Content-Type becomes text/plain
Javascript code to implement different objects can be found here
If you're using Chrome and you're trying to set the content-type header, you'll probably have some issues due to security restrictions:
Uncaught DOMException: Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
See sendBeacon API not working temporarily due to security issue, any workaround?
I want to call an api when someone close the tab, so I tried to use navigator.sendBeacon() but the problem is we need to pass the Authorization token into it and sendBeacon does not provide that, so I found other solution that is more effective and very easy to implement.
The solution is a native fetch API with a keepalive flag in pagehide event.
Code
window.addEventListener('pagehide', () => {
fetch(`<URL>`, {
keepalive: true,
method: '<METHOD>',
headers: {
'content-type': 'application/json',
// any header you can pass here
},
body: JSON.stringify({ data: 'any data' }),
});
});
FAQs / TL;DR Version
Why should we need to use the keepalive flag?
The keepalive option can be used to allow the request to outlive the page. Fetch with the keepalive flag is a replacement for the Navigator.sendBeacon() API.
Learn more about it, please visit https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters
What is PageLifecycle API
Learn more about it, please visit https://developer.chrome.com/blog/page-lifecycle-api/
From the Page Lifecycle image, shouldn't unload be considered as the best choice?
unload is the best event for this case but unload is not firing in some cases on mobile and it also does not support the bfcache functionality.
I also notice that when I am using unload then I am not getting proper output in the server log. why? IDK, if you know about it then comments are welcome.
Nowadays, It's also not recommended by the developers.
Learn more about why unload is not recommended: https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event#usage_notes
Learn more about pagehide: https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
Because the method sendBeacon(..) does not allow headers manipulation, I added them into the form as normal fields:
const formData = new FormData();
formData.append('authorization', myAuthService.getCachedToken());
navigator.sendBeacon(myURL, formData);
Then on the host side I added a simple Middleware class (.Net) which catches POST requests without headers and copies them from the body:
public class AuthMiddleware
{
...
...
public async Task Invoke(HttpContext context)
{
string authHeader = context.Request.Headers["Authorization"];
if (authHeader == null && context.Request.Method=="POST")
{
context.Request.Headers["Authorization"] = string.Format("Bearer {0}",
context.Request.Form["authorization"].ToString());
}
await _next.Invoke(context);
}
}
Posting as an answer as I'm not allowed to post a comment under the answer:
For Chrome, issue with navigator.sendBeacon sending Blob for with non CORS-safelisted types was fixed in Chrome version 81 so this should be safe to use now.
https://bugs.chromium.org/p/chromium/issues/detail?id=724929
For IE, an alternative in unload event is to use synchronous ajax request, as IE doesn't support sendBeacon but supports synchronous ajax call in my case.
You can't send data with JSON after Chrome 39, has been disabled due to a security concern.
You can try to send data with plain text. But don't forget the parseing text from the backend.
After searching for an answer for this question I found out that for passing header with navigator we need to pass a blob object.
For example
var headers = {type: 'application/json'};
var blob = new Blob(request, headers);
navigator.sendBeacon('url/to/send', blob);

Converting cURL to JQuery.ajax request

Hi I'm working on connecting to an API that is using Layer 7 as an IP authorizer and eGalaxy as a credentials authorizer, when the curl request is sent a line of xml is sent back to me. I'm currently working on localhost, I've implemented the Access-Control-Allow-Origin chrome extension.
My curl request looks as such:
curl https://client-url/eGalaxy.aspx -H 'Content-Type:text/html' --data '<?xml version:"1.0" encoding="UTF-8"?><Envelope><Header><SourceID>0</SourceID><MessageID>131</MessageID><MessageType>Authenticate</MessageType></Header><Body><Authenticate><Username>*username*</Username><Password>*password*</Password><PasswordEncrypted>NO</PasswordEncrypted></Authenticate></Body></Envelope>' --insecure
When I tried to create an ajax request I receive an "Invalid HTTP status code 500" error and "OPTIONS url" which drops down to show:
n.ajaxTransport.k.cors.a.crossDomain.send # jquery-2.1.3.js:4
n.extend.ajax # jquery-2.1.3.js:4
(anonymous function) # VM947:2
InjectedScript._evaluateOn # VM899:895
InjectedScript._evaluateAndWrap # VM899:828
InjectedScript.evaluate # VM899:694
My ajax code is as follows:
$.ajax({
url:'https://client-url/eGalaxy.aspx',
data:'<?xml version:"1.0" encoding="UTF-8"?><Envelope><Header>
<SourceID>0</SourceID><MessageID>131</MessageID>
<MessageType>Authenticate</MessageType></Header><Body>
<Authenticate><Username>*username*</Username>
<Password>*password*</Password>
<PasswordEncrypted>NO</PasswordEncrypted></Authenticate></Body>
</Envelope>',
type:'POST',
contentType:'text/xml',
dataType:'xml',
success: function(data){
},
error: function(){
}
});
Any help with translating into a proper AJAX request would be appreciated!
EDIT: If this makes a difference these are the headers that are returned with the client's xml when the curl is complete(client information deleted)
This application will be made into a widget as well, so it will not be running off of a hosting site.
UPDATE 1: I'm using #KevinB's suggestion that the CORS headers were still not properly added.
Here is my updated JS code, copied from this link:
var url = 'https://client-url/eGalaxy.aspx';
var data = '<?xml version="1.0" encoding="UTF-8"?><Envelope><Header><SourceID>1</SourceID><MessageID>131</MessageID><MessageType>Authenticate</MessageType></Header><Body><Authenticate><Username>*username*</Username><Password>*password</Password><PasswordEncrypted>NO</PasswordEncrypted></Authenticate></Body></Envelope>';
var xhr = createCORSRequest('POST', url);
xhr.send(data);
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Check if the XMLHttpRequest object has a "withCredentials" property.
// "withCredentials" only exists on XMLHTTPRequest2 objects.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// Otherwise, check if XDomainRequest.
// XDomainRequest only exists in IE, and is IE's way of making CORS requests.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// Otherwise, CORS is not supported by the browser.
xhr = null;
}
return xhr;
}
var xhr = createCORSRequest('GET', url);
if (!xhr) {
throw new Error('CORS not supported');
}
When run with the CORS Chrome extension off I receive an Access-Control-Allow-Origin =! 'null' error. Knowing that CORS needs Access-Control-Allow-Origin header to =! 'null' will this cause problems in the future with making this into a widget that will be put into a Content Manager system?
With it on the origin is set to 'www.evil.com', with the only error in the code being that it says the xhr.send() is an anonymous method. Using breakpoints I can see the xhr in xhr.send() is set to an empty request:
> XMLHttpRequest {response: "", responseText: ""}
Inside the createCORSRequest this line is undefined. I've tested using 'GET' and 'POST' as the method.
xhr.open(method, url, true)
EDIT 2:
Using #Fabiano's approach I've changed the web.config for two versions of what I suspect is my server(?). I'm attaching screenshots of what I've gone through
No luck, so far. Decided to use xhr.AppendHeader:
I decided to use xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
The Network tab Headers for eGalaxy.aspx
There is an error in your XML. You put version:"1.0", and this makes the XML invalid.
Change to version="1.0" and try to make your request. It should work.
This may be the cause for the "Bad request" error.
You can validate your XML here: enter link description here
EDIT: After some research, the problem may be with the headers sent by your server. Your server (or page, .aspx in this case) seems to skip the header you need, the "Access-Control-Allow-Origin: *".
Look at this link: http://enable-cors.org/server.html
This site shows you how to implement it for your server. Since the page you are requesting is called eGalaxy.aspx, then you have 2 ways to implement the headers:
1- Put the line Response.AppendHeader("Access-Control-Allow-Origin", "*"); if the page is a simple ASP.NET application. If it uses Web API 2, you need to implement a different way as it is shown here: http://enable-cors.org/server_aspnet.html
2- Edit the web.config file on the root of your server and add these lines inside the tag:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
For a ASP.NET application, these are the ways you have. The link I mentioned has solutions for other applications, take a look and choose the right one. :)
Note that the value * tells you that your server will accept any cross-origin request. This may lead to a security issue, so the best you can do is to put your domain address instead of *.
I hope it helps!

Cross domain XHR failing

I have an API hosted on one domain that has CORS enabled with the following headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 1728000
I am able to make a GET or POST request from hackst.com and it works fine. Link: http://hackst.com/#w3SbV
From my backbone app hosted on another domain, GET requests work fine. But when I try to create and save a new model (i.e. make a POST request), it fails with the following error:
Failed to load resource: the server responded with a status of 501 (Not Implemented) http://projectwhatup.us:5000/api/posts
XMLHttpRequest cannot load http://projectwhatup.us:5000/api/posts. Origin http://ayush.projectwhatup.us is not allowed by Access-Control-Allow-Origin.
My relevant backbone code:
var newPostData = {
topic : "New Post",
body : "new body",
user_id : 1,
};
var newPostModel = new Post(newPostData);
this.model.create(newPostModel);
I even tried over-riding the create method and making a POST request manually like this:
create : function(data) {
console.log('overriden create');
$.ajax({
"url" : this.url,
"async" : true,
"beforeSend" : function(obj){
console.log(obj);
},
"contentType" : 'application/json',
//"crossDomain" : true, // uncommenting this doesnt help either
"headers" : {
},
"dataType" : 'json',
"type" : 'POST',
"data" : JSON.stringify(data),
"error" : function(err){
console.log('new post creation failed');
console.log(err);
},
"success" : function(resp){
console.log('new post created');
console.log(resp);
}
});
}
Same error.
I tried a stand-alone GET request on JSFiddle as well (http://jsfiddle.net/X9cqh/5/), but that fails even though my backbone app can make the GET request fine.
I'm completely clueless at this point. Any hints, pointers, solutions?
The server should also reply to the preflight with the following header:
Access-Control-Allow-Headers: Content-Type
This is necessary because the content type is application/json, which is outside the acceptable values defined in the CORS spec (http://www.w3.org/TR/cors/).
Your sever setup works. JSFiddle apparently does not make the ajax requests, but you can quickly test that it works by entering these four lines into Chrome console or Safari developer console:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://projectwhatup.us:5000/api/posts', false);
xhr.send();
xhr.responseText;
If you try this with a domain that does not allow CORS, it will error out.
The reason that adding a 'Content-Type' header makes your CORS request fail is because your server is set up wrongly.
If the client wishes to specify particular headers or use an unusual http method verb (e.g. PUT), then the browser will first do a 'preflight' OPTIONS call to ensure that it is allowed to set those headers. Your server needs to respond to this OPTIONS call with the appropriate headers. You'll see that options call in the network tab of the Chrome developer tools or firebug if you want to confirm that this is what the problem is.
You may be interested in my more detailed answer here.

Categories