Is there a way to get the Response Headers of WebSocket request? - javascript

On a Network tab (Chrome browser) we can see a Headers tab.
Further if we have a request list we see General, Response Headers and Request Headers lists.
For example:
General:
Request URL: wss://some.url.com/websocket
Request Method: GET
Status Code: ...
Response Headers:
OWN-KEY-FROM-SERVER: true
etc...
If that was a XMLHttpRequest, we can use getAllResponseHeaders method of xhr, but WebSocket doesn't have something like this according to the WebSocket API.
I need to get from server some trigger and he is inside Responses Headers list.
Maybe somebody know a decision with that.

If using chrome is not the only option for you, then:
I used wireshark to manitor my websocket traffic. It included all the headers and bodies and works perfectly. Just set filter for tcp.port==YOUR_PORT || (websocket) and start manitoring.

Related

Making Get request to Yammer API works using Postman tool but not with Vue-Resource

I am trying to integrate Yammer API in my Vue.JS project, for Http calls I am using Vue-Resource plugin. While making GET Http call to get posts from Yammer it gives me following error -
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
I tried postman tool and that gives successful response, but when I try to run the same thing in my Vue.JS project using Vue-Resource plugin it wont work.
The Vue.JS code snippet -
function(){
this.$http.get("https://www.yammer.com/api/v1/messages/my_feed.json").then((data)=>{
console.log(data);
});
In main.vue file i have -
Vue.http.interceptors.push((request, next) => {
request.headers.set('Authorization', 'Bearer my_yammer_token')
request.headers.set('Accept', '*/*')
next()
})
Then I tried the code snippets provided by Postman tool for jquery, that too not working.
jQuery code -
var settings = {
"url": "https://www.yammer.com/api/v1/messages/my_feed.json",
"method": "GET",
"timeout": 0,
"headers": {
"Authorization": "Bearer my_yammer_token",
"Cookie": "yamtrak_id=some_token; _session=some_token"
},
};
$.ajax(settings).done(function (response) {
console.log(response);
});
Though, I found similar questions but nothing worked for me.
I am working this to resolve from last 2 days but getting failed again and again. Please guide/help me.
A browser has higher security requirements than a request in PostMan. In a browser, you are only allowed to make XHR requests to your own current host (combination of domain + port) but not to other remote hosts. To nevertheless make a request to a remote host, you can use the browser built-in CORS. By using this, your browser makes a pre-flight request to the remote host to ask if the current page is allowed to request from that host. This is done via the Access-Control response headers. In your case, this header is probably missing or not allowing your page to access, which is why the request does not go through. Please read further into that topic.
However, in your case, using CORS probably won't be a solution for two reasons: To use CORS, the remote host must present a header which allows every requesting host (*) or your specific one. If you cannot set that setting anywhere on the remote host, it won't work. Second, it is not safe to place your authorization token into client-side JavaScript code. Everybody can just read your JS code and extract the authorization token. For that reason, you usually make the actual API call from the server-side and then pass the data to the client. You can use your own authentication/authorization against your server and then use the static authorization key on the server to request the data from the remote host. In that case, you'll never expose the authorization key to your user. Also, on the server-side, you do not have to deal with CORS as it works just like PostMan or curl as opposed to a browser.

Axios how to set form data similar to jQuery ajax method?

I'm using axios in my application, but I'm having a hard time setting the content of the request.
There's currently a call to a URL using $.ajax like this:
$.ajax({
method: 'POST',
data: { 'accountId': accountId },
url: serverUrl,
/* success: ... */
});
And when I look at this request in Chrome dev tools, at the end I see something like this:
Now, I'm trying to do the same thing with axios:
axios.post(serverUrl, { accountId: accountId })
.then(/* ... */);
But, when I look at the request in Chrome dev tools, I have this:
How can I get axios to do the same formatting as jQuery? And maybe the question is that: are they different or it's just the representation?
Also, I noticed that the jQuery call is somehow adding this header: x-requested-with: XMLHttpRequest, but to have the same header in axios, I have to set it manually. Is it normal? Am I missing an axios configuration to add this header?
Thank you
Some frameworks use this header to detect XHR requests, for example. Grails Spring uses this header to identify the query XHR and gives the JSON response or the HTML response as a response.
Most Ajax libraries (Prototype, JQuery and Dojo from version 2.1) include the X-Requested-With header, which indicates that the query was made using XMLHttpRequest instead of running by clicking a regular hyperlink or submitting a form button.
A good reason for security is that it can prevent CSRF attacks, because this header can not be added to the cross domain of the AJAX request without the server's consent through CORS.
Only the following headers are allowed:
To accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
any others call the "before flight" request in the browsers supported by CORS.
Without CORS, X-Requested-With can not be added to an XHR request with a cross domain.
If the server checks the presence of this header, it knows that the request did not initiate an attempt to make a request on behalf of the user from the attacker's domain using JavaScript.
It also checks that the request was not sent from the usual HTML form, from which it is more difficult to verify that it is not a cross domain without the use of tokens. (However, checking the Origin header can be an option in supported browsers although you leave old browsers vulnerable.)
See also: https://markitzeroday.com/x-requested-with/cors/2017/06/29/csrf-mitigation-for-ajax-requests.html
So also read for greater understanding:
FormData()
https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData
Request Payload
What's the difference between "Request Payload" vs "Form Data" as seen in Chrome dev tools Network tab
As documented here, You can use the URLSearchParams API to send data in the application/x-www-form-urlencoded format using axios.
Example from offical docs:
var params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);

Fetch - respond to preflight response

I am struggling with fetch over CORS, with authorization:
const token = 'this.is.secret!';
fetch('http://corsserver/api/hello', {
method: 'get',
credentials: 'include',
mode: 'cors',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(response => {
console.log(response);
}).catch(error => {
console.log(error);
});
When I run this request, Chrome sets the header as:
Request Method:OPTIONS
I look this up and it's a preflighted request.
I mean, that's really cool and stuff. However I can't figure out how to send the actual request after the preflight comes back okay! What's the next step? How do I send the GET request?
I'm missing something very basic here.
Browsers will automatically send the actual GET request if the OPTIONS request is successful. But if the OPTIONS request isn’t successful, browsers will never make the GET request.
And there’s no way make that GET request without the browser doing the OPTIONS request.
So if the browser isn’t doing the GET, it can only mean the OPTIONS must be failing, and you need to find out why. The browser should be logging a message with the reason to its devtools console, so you should start by checking there (and then either edit/update the question to add that info, or post a new separate more-specific question with the error message).
One guess for what the problem could be: Maybe the server is requiring authentication for the OPTIONS request. If so, you need to fix it so that the server doesn’t—because when the browser makes the OPTIONS request, it doesn’t send the Authorization header+value from your code.
Instead in fact the whole purpose of the OPTIONS request in this case is for the browser to ask, Are you OK with getting cross-origin requests that have an Authorization request header?, and for the server to respond in way that indicates if it allows the Authorization header.
So because of that, the server must be configured to respond to any OPTIONS requests (from allowed origins at least) with a 2xx success response, without requiring authentication.
The way you’d know whether the server is requiring authentication for that OPTIONS request is if the CORS message your browser is logging shows a 401 status for the OPTIONS response.
Example code for handling the OPTIONS in a Node.js server environment:
if (req.method === 'OPTIONS') {
res.send();
return;
}
…to make the server send a 200 response with no response body, which is what you want for this. Do note that this explicitly allows all OPTION requests.

Sending a 'simple' POST request with jQuery, but getting CORS anyway

The CORS specification states that if a HTTP request is considered 'simple', no CORS and/or preflight is needed.
I'm trying to do a HTTP request that appears to have these conditions:
I'm not setting custom HTTP headers.
I'm using a POST method.
I'm using application/x-www-form-urlencoded.
Code sample:
$.ajax({
type: 'POST',
url: 'http://example.org/',
data: {foo: 'bar'}
});
However, when running this, the request is still preflighted with OPTIONS (which fails). Is there something obvious I'm missing?
A few references to simple requests:
https://w3c.github.io/webappsec-cors-for-developers/#cross-origin-send-permissions-simple-safelisted-request
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests
CORS restrictions affect all requests going from one domain to another. example: localhost -> example.com. I end up just going to my example.com server-side code and make sure I enable requests from myotherexample.com where I am making calls from. Do this using the CORS header while developing locally
Access-Control-Allow-Origin: *
Another example when you are ready for production
Access-Control-Allow-Origin: https://myotherexample.com
I realized my mistake when re-reading the documentation.
What I am doing is indeed a simple request.
The request was actually being sent to the server without an OPTIONS request and succeeded!
However, I was not allowed to read the response when it came back. So the true difference between simple and non-simple CORS requests is:
For simple requests a preflight is not needed, but the server still needs to respond with CORS headers.
So my options are as follows:
I ignore the error. The request succeeded after all, I just can't read the response.
I implement CORS server-side anyway. In my case I can't, because I don't control the target server.
I use a html form to submit the data, call .submit() on it and target a hidden iFrame.
I proxy the request through a server that I do control.
Future:
I think, but I'm not sure, that the new Fetch API also allows a mode where you can make HTTP requests cross-domain, opt-out of CORS and simply be denied access to the HTTP response. If this is correct, then this would be the ideal way to do this (to me). But I don't know 100% certain if this is indeed how this works.

get SENT headers in an XMLHttpRequest

Trying to get the Request headers from the XHR object, but with no luck, is there a hidden method or property of that object that will expose the headers sent by the browser?
I already know how to set custom request headers and view the response headers, I'm looking to get a list of all REQUEST headers sent, ones created by the browser and my custom ones.
I'm using webkit/chrome, don't care about other browsers.
EDIT: I'm not looking to monitor the request, I'm building a web app and I need to list those headers and display them within the app, please don't tell me about fiddler, firebug and chrome tools, that's not what I'm looking for.
There is no method in the XMLHttpRequest API to get the sent request headers. There are methods to get the response headers only, and set request headers.
You'll have to either have the server echo the headers, or use a packet sniffer like Wireshark.
Try using Fiddler Web Debugger.
http://www.fiddler2.com/fiddler2/
You can capture the request that was sent in any browser as well as inspect the request headers, response headers, and even copy a capture sent request and send it out as your own.
Assuming you are using jQuery, and you're looking for anything attached, but maybe not ALL headers sent, this could help. Not sure if it meets your exact needs, (since the browser tends to add its own things), but if you need to grab your own headers first, this works:
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
if(!(settings.headers && settings.headers.token)) {
//no token header was set, so set the request header
jqXHR.setRequestHeader('token', newtoken);
}
}
})
As the name suggests, sent headers were SENT, (duh)! And the XMLHttpRequest class doesn't store sent headers in RAM or put sent headers in an instance of XMLHttpRequest... which is good for performance.
If you want to get the headers that have been sent, all you need to do is to create a log mechanism.
And since custom request header are created through XMLHttpRequest.prototype.setRequestHeader(), You need to intercept XMLHttpRequest.prototype.setRequestHeader();
var sentHeaders = {}
var originalXMLHttpRequest_setRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
sentHeaders[header] = value;
originalXMLHttpRequest_setRequestHeader.call(this, header, value);
}
That's all. No need for external library nor Wireshark. All done within Javascript;
Just make sure the intercept code above executed before any XMLHttpRequest initialization.
Ps. this code will obviously only intercept the custom header created through setRequestHeader(). The XMLHttpRequest itself will set some default headers which can't be accessed through this method.

Categories