NODEJS: How do I read Body Parameters with Restify? - node.js

I'm new to Node/Restify and must be missing something stupid here, but I've been banging my head on this for awhile. Hopefully someone can help.
I'm trying to read Body parameters from a POST request with restify. Everything I find seems to suggest that all I need is server.user(bodyParser()), but its not working and I don't know why, and I'm not really sure how to troubleshoot further.
Can anyone help point me in the right direction on what I'm doing wrong here?
I created a simple server like follows:
var restify = require('restify');
var server = restify.createServer();
server.use(restify.bodyParser());
server.post("/test", function(req, res){
console.log(req.params);
console.log(req.body);
res.send(200);
res.end();
});
server.listen(8081);
I then ran the following POST request:
POST /test?GET_PARAM=def HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 33
POST_PARAM1=abc&POST_PARAM2=ghi
This results in the following in the console:
debugger listening on port 49953
{}
undefined
If I include queryParser, I can get the GET parameters without a problem, but what I really want is the post parameters either as straight standard params (like my example), or as JSON. I've tried the request both ways.
e.g. This gives the same response in the console:
POST /test?GET_PARAM=def HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 44
{ POST_PARAM1: 'abc', POST_PARAM2: 'ghi' }

I believe I've had the same frustrating problem in the past: A missing Content-Type header. Restify will just ignore any content if the header is not there. Your JSON example should have:
Content-Type: application/json
Not sure about your first example, perhaps multipart/form-data see this question.
Also: Your JSON example isn't valid JSON. You need to have double quotes around the keys and the values like so:
{
"POST_PARAM1": "abc",
"POST_PARAM2": "ghi"
}
A good tool for interfacing and building requests for this type of stuff is Postman, as it adds those headers automatically when you build the body and choose the type.

Related

Why is Safari sometimes, but not always, throwing a cors error when posting to my nodejs API?

I am working as part of a team to design a website where users can either upload an existing video, or record a new video file in-browser. Selecting a file for upload is done with a standard html form, while recording uses react-video-recorder. In either case, once the file is ready, the form is submitted using a ky post request.
const response = await ky.post(`https://xxx.xxx.xxx.xxx:xxxx/upload`,
{
timeout: false,
body: formData,
headers: {
'Authorization': `Bearer ${sessionStorage.getItem('token')}`
}
}).json();
Both methods of adding a file go through this same function, so the headers on the post request will be literally the same regardless of how the user added their video.
Despite this, Safari will throw a cors error only when attempting to upload a video recorded with react-video-recorder. This does not occur when attempting to record and post a video using Chrome for Mac on the same page.
I have checked on the server side, and I am specifically setting the headers to allow the site - I even tried literally copying the "origin" header of the request into the value for "Access-Control-Allow-Origin", just in case I'd made a typo
app.post('/upload',
passport.authenticate('jwt', {session: false}),
function(req,res) {
res.setHeader('Access-Control-Allow-Origin','https://my-website.com')
res.setHeader('Access-Control-Allow-Methods','POST, GET, OPTIONS')
...
At this point, I'm wondering if it's actually a cors issue at all, or if there's something else messed up and Safari is just giving me profoundly unhelpful error messages while I'm troubleshooting. Does anyone have any ideas or tips they can give me?
EDIT: I was able to copy the contents of the http requests, and they are different - I just don't know why...
The successful request is:
POST /upload HTTP/1.1
Accept: application/json
Origin: https://my-website.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGRcSY52tKpQVBLIb
Authorization: Bearer _redacted
Referer: https://my-website.com/
Content-Length: 51199
Host: my-api.com:3004
Accept-Language: en-ca
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
The failed request:
POST /upload
Authorization: Bearer _redacted
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary0Uzp1dEaDyHuIhEw
Accept: application/json
Origin: https://my-website.com
Referer: https://my-website.com/Upload
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15
Does this indicate that the video file wasn't successfully attached to the post request?

Websocket Connection Failed

Im trying to create a websocket server using net in Node.js. In the chrome console im getting an error that simply says "WebSocket Connection Failed!" and dosent show an error code or any other details. As far as i can tell ive don the handshake correctly, but the connection still fails anyway and im not certain why.
Heres the HTTP request my client sent (via WebSocket API) -
GET /chat HTTP/1.1
Host: localhost:3000
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Linux; Android 7.0; AGS-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Safari/537.36
Upgrade: websocket
Origin: http://localhost:3000
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,es;q=0.8,ar;q=0.7,hy;q=0.6,mi;q=0.5
Sec-WebSocket-Key: shhs88pGIFyzpQgczYc3uw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
And heres the response my server sends back. Ive followed each step correctly according to the docs.
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: RDoXJ7C3/oDQLkUyHc2BFYdevY8=
I know there isnt anything wrong with the client code, since the WebSocket API handles the nitty gritty for me. There must be somthing im missing with the handshake on the servers side but, i still dont see what. I apreciate if anyone can point anything out i may have missed.
All fixed. According to the specs, each HTTP header must be folowed by a line termination (\r\n). My mistake was that in didn't add a double line break, which is supposed to come after the headers.

Granting READER role access to a Subscription in Azure works fine in Postman, but not via Angular. Why?

OK, I might be missing something simple here in Angular, but I could really use some help. I am trying to grant a Service Principal READER role to a Subscription programmatically. If I use PostMan, it works fine. However, when I send the same PUT request via Angular6 I get a 400 error from Azure that says:
The content of your request was not valid, and the original object
could not be deserialized. Exception message: 'Required property
'permissions' not found in JSON. Path 'properties', line 1, position
231.'
The JSON being sent in both cases is:
{
"properties":
{
"roleDefinitionId":"/subscriptions/{some_subscription_guid}/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7",
"principalId":"{some_service_provider_guid}"
}
}
I've captured traffic from both requests, and they show as application/json payloads on the PUT. So I am at a loss of what is deserializing incorrectly through Azure that is causing this error. I am trying to follow the REST instructions documented here: https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-rest
Any ideas what I am missing?
UPDATE
Adding the RAW REQUEST per request. I have replaced any sensitive data (access token, GUIDs etc) without changing anything else from the Fiddler output.
PUT https://management.azure.com/subscriptions/<VALID_SUBSCRIPTION_WAS_HERE>/providers/Microsoft.Authorization/roleDefinitions/7ec2aca1-e4f2-4152-aee2-68991e8b48ad?api-version=2015-07-01 HTTP/1.1
Host: management.azure.com
Connection: keep-alive
Content-Length: 233
Accept: application/json, text/plain, */*
Origin: http://localhost:4200
Authorization: Bearer <VALID_TOKEN_WAS_HERE>
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Content-Type: application/json
Referer: http://localhost:4200/token/<VALID_DOMAIN_WAS_HERE>.onmicrosoft.com/graph
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
{"properties": { "roleDefinitionId":"/subscriptions/<VALID_SUBSCRIPTION_GUID_HERE>/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", "principalId":"<VALID_OBJECTID_HERE>" }}
Alright, I finally figured out what was going on here. It appears that I was posting to the wrong endpoint. I need to be posting to roleAssignment and not roleDefinitions.
So why did it work in PostMan? It seems there is a fallback from a previous version of the API that supported both when using legacy clients, which for some reason PostMan fell under. However, when posting via Angular it was actively rejecting it.
End result... send to "/Microsoft.Authorization/roleassignments/" with an API version later than "api-version=2015-07-01". All will work.

Self-Coded Proxy cannot retrieve image from wikipedia

I'm trying to write a small proxy server in c#. It is working nicely for many webpages I tested (including google.com and microsoft.com). For testing I started my proxy server and configured IE 10 on Windows 8 to use it.
But when I try wikipedia.org it does only load the main page but no pictures. I tried to load a single picture (http://upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png). When I use IE without proxy it works, but with the proxy I get a 404 response.
This is the GET Request which IE (my proxy just forwards it) issues:
GET http://upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png HTTP/1.1
Accept: text/html, application/xhtml+xml, */*\
Accept-Language: de-CH\
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Accept-Encoding: gzip, deflate
Host: upload.wikimedia.org
DNT: 1
Proxy-Connection: Keep-Alive
IMHO it looks correct. This is the response I get (omited some html tags):
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=UTF-8
X-Varnish: 1427845074 1427806476, 274786836, 3671934588
Via: 1.1 varnish, 1.1 varnish, 1.1 varnish
Content-Length: 262
Accept-Ranges: bytes
Date: Mon, 01 Jul 2013 21:30:54 GMT
Age: 28
Connection: keep-alive
X-Cache: cp1063 hit (1), cp3004 miss (0), cp3003 frontend miss (0)
Access-Control-Allow-Origin: *
...404 Not Found\n The resource could not be found.\nRegexp failed to match URI: "http:/upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png"
The strange part is here:
Regexp failed to match URI: "http:/upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png"
-> the URL starts with a http:/
In the code I connect to uploads.wikimedia.org like this:
// connect to uploads.wikimedia.org
ServerSocket.Connect(RemoteHost, 80);
byte[] SendBuffer = Request.ToArray();
// send the clients request to the server
ServerSocket.Send(SendBuffer);
I have no idea why it doesn't work. Any help is appreciated. My full code is located on Github: Proxy_C_Sharp
I just found out why.
According to the HTTP/1.1 specification (http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5) in Chapter 5.2.1:
"To allow for transition to absoluteURIs in all requests in future versions of HTTP, all HTTP/1.1 servers MUST accept the absoluteURI form in requests, even though HTTP/1.1 clients will only generate them in requests to proxies."
I tried it out with a small tool. if I make a request like this:
GET /wikipedia/commons/6/63/Wikipedia-logo.png HTTP/1.1
Host: upload.wikimedia.org
It works. So the reason is that Wikipedia is not conform to the standard. It should accept absolute urls. But it works if I visit the site without a proxy because the browser uses absolute URIs only with proxies. If there is no proxy configured it uses a relative one.

Uploading to another domain gives HTTP code 405

I'm trying to upload a file (which can be quite large) from the website of one server to the backend of another server using plupload. Lets say:
domain 1 = http://www.websitedomain.com/uploadform
domain 2 = http://www.backenddomain.com/uploadhandler
Trying to upload i send the following:
OPTIONS /main/uploadnetwork.php HTTP/1.1
Host: backenddomain.com
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://www.websitedomain.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4
Access-Control-Request-Headers: origin, content-type
Accept: */*
Referer: http://www.websitedomain.com/uploadform
Accept-Encoding: gzip,deflate,sdch
Accept-Language: nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
DNT: 1
But when I try to start the upload the server returns the following:
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS, TRACE
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
X-Powered-By-Plesk: PleskWin
Date: Mon, 01 Oct 2012 12:41:57 GMT
Content-Length: 999
After doing some research I found out that a browser does this to check if the server will accept the intended message. It looks like my server doesn't feel like accepting a simple POST call even tho i use post all the time.
The Google Chrome console gives the following error:
XMLHttpRequest cannot load http://www.backenddomain.com/uploadhandler. Origin http://www.websitedomain.com is not allowed by Access-Control-Allow-Origin.
Does anyone know how to stop the browser from checking or how i can tell my server to just accept the POST?
You seem to face a Same origin policy problem
Adding a special header should help on some browsers :
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
Answers to this question might also be helpfull :
Cross-domain data access in JavaScript
You should also check the cross-domain tag : https://stackoverflow.com/questions/tagged/cross-domain

Resources