Serving pre-flight request using ExpressJS - javascript

I created a simple route in express using the code below.
const express = require("express");
const app = express();
app.get('/route1', (req, res) => {
res.send({ data: "Route 1" });
});
app.listen(3000);
When I run curl -X GET http://localhost:3000/route1, I am getting {"data":"Route 1"} as response.
However, I tried running curl -X OPTIONS http://localhost:3000/route1 to simulate a CORS pre-flight request. I received GET,HEAD as the response.
I was not able to find any documentation supporting this behaviour. Why did the above route respond to OPTIONS request?
(NOTE: I haven't used any other packages like CORS)
EDIT
Based on Quentin's answer, I tried issuing another OPTIONS request with relevant headers and with display headers flag in curl.
curl -i -X OPTIONS http://localhost:3000/route1 \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-requested-with'
HTTP/1.1 200 OK
X-Powered-By: Express
Allow: GET,HEAD
Content-Type: text/html; charset=utf-8
Content-Length: 8
ETag: W/"8-ZRAf8oNBS3Bjb/SU2GYZCmbtmXg"
Date: Wed, 03 Jul 2019 11:14:07 GMT
Connection: keep-alive
GET,HEAD

OPTIONS is a standard HTTP method with standard behaviour that has built-in support in Express.
The CORS spec layers additional semantics over the top of a regular OPTIONS request.
curl -X OPTIONS http://localhost:3000/route1 makes an OPTIONS request, but it isn't simulating a prefight request (as it is missing a bunch of request headers that are required by the CORS specification). The response you get to that request doesn't include any CORS response headers either.
Re edit:
I tried issuing another OPTIONS request with relevant headers
You missed out the Origin header, but as you can see, since you didn't set up CORS support in the Express app, the response still doesn't include any CORS response headers.

Related

Getting error when using mimik's first-edge-microservice

I am working on a code to allow your microservice to retrieve your network’sEdge Cloud Engine linkLocal clustering information as in the mimik's page but after making the HTTP call from curl i am getting the following issue.
starter-microservice\build>curl -i -H "Authorization: Bearer "
http://localhost:8083/localDevices
HTTP/1.1 404 Not Found
Cache-Control: no-cache, no-store, must-revalidate, private, max-age=0
Pragma: no-cache
Expires: 0
Content-Type: text/plain; charset=utf-8
Date: Thu, 14 Jan 2021 07:36:33 GMT
Connection: close
Error 404: Not Found
Not Found
Is the microservice you are trying to call developed by you or is it the starter-microservice found here on mimik github ?
If its your own microservice then you need to call the right endpoint. One of the reasons you're getting 404 is because the endpoint cannot be found. You also need to provide the JWT token you received during edge association using OAuth Tool. You have to put the token right after the words 'Authorization: Bearer YOUR-JWT-TOKEN' in your curl command.
Please follow these tutorials in the order they appear:
https://developer.mimik.com/development-setup/
Once you've finished this please copy the "edge Access Token” this is the
JWT token mentioned earlier.
If you have your own microservice you would like to deploy then you need to follow the instructions here: https://developer.mimik.com/deploying-edge-microservice/ if not then clone this repo from mimik Github and follow the instructions in the README.md

Error when GET HTTPS from REST API in Angular

I have an Angular app running which uses an external api to get countries ISOs.
This API uses https and it's giving me an error.
The thing is: when I use a proxy in my angular local environment, mapping /iso-api/ to the real url it works ok.
"/iso-api/*": {
"target": "https://www...",
"pathRewrite": { "^/iso-api": "" },
"secure": false,
"changeOrigin": true,
"logLevel": "debug"
}
But I want this to work in production, so I want to use the real url.
In my server I am returning the Access-Control-Allow-Origin: * header already.
I've tried to run the angular server with ssl (as the external api uses https), but I receive the same error.
I know a solution would be to implement the proxy in the server, but I believe this should not be done and there may be a way to retrieve this data from the frontend.
Help please.
Response
This is the network error in Chrome:
In Firefox, the request ends with 200 OK and returns data, but CORS error is thrown and I cannot access the data from the app: CORS header 'Access-Control-Allow-Origin' missing
General
Request URL: https://www...
Referrer Policy: no-referrer-when-downgrade
Request headers
:method: GET
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: es-ES,es;q=0.9,en;q=0.8
origin: http://localhost:4200
referer: http://localhost:4200/app/login
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
Response headers
accept-ranges: bytes
cache-control: max-age=0
content-encoding: gzip
content-language: en-US
content-length: 68356
content-type: application/json
date: Mon, 27 Apr 2020 14:49:30 GMT
expires: Mon, 27 Apr 2020 14:49:30 GMT
referrer-policy: strict-origin-when-cross-origin
server-timing: cdn-cache; desc=HIT
server-timing: edge; dur=1
server-timing: ACTT;dur=0,ACRTT;dur=88
set-cookie: ... expires=Mon, 27 Apr 2020 16:49:30 GMT; max-age=7200; path=/; domain=...; HttpOnly
set-cookie: ... Domain=...; Path=/; Expires=Mon, 27 Apr 2020 18:49:30 GMT; Max-Age=14400; HttpOnly
set-cookie: ... Domain=...; Path=/; Expires=Tue, 27 Apr 2021 14:49:30 GMT; Max-Age=31536000; Secure
status: 200
vary: Accept-Encoding
UPDATE
Angular service code
import { HttpClient } from '#angular/common/http';
...
constructor(
private _http: HttpClient,
private _errorUtil: ErrorUtilService,
private _converter: StoreConverter
) {}
...
getCountries(): Observable<CountryWithLanguages[]> {
return this._http.get<GetStoresResponse>(API.storeUrl).pipe(
catchError(this._errorUtil.handle),
map(result => result.stores),
switchMap(stores => stores),
filter(this._isActiveStore),
map(store => this._converter.toView(store)),
toArray()
);
}
To serve the app I use angular dev server, I do not add the 'Access-Control-Allow-Origin' header manually but, in the browser, I see that it is being added.
angular.json
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "push-web-app:build",
"proxyConfig": "src/proxy-local.conf.json"
},
}
You can't request a resource from another domain. This would be a security hole. You can read more here: Same-origin policy
Sending Access-Control-Allow-Origin: * from your server won't give you access to the aforementioned API. The provider of this API needs to give you permission to access the API, you can't give yourself this permission.
The error you posted states that the Access-Control-Allow-Origin header is missing. It means that the API isn't sending this header.
There might be two reasons why this API isn't sending Access-Control-Allow-Origin header.
A misconfiguration on the side of this API. In this case you have to ask the provider of this API to fix this issue.
The API provider is restricting access to the API on purpose. In this case you have to ask the provider of this API to give you access from your domain.
You can also proxy the request through your server. The core difference when using proxy is that your server reads the resource from the API and not the client browser. See David's response on how to configure proxy with nginx.
You cannot bypass CORS browser side. If you are not able to modify the server side, your only solution is to use a proxy.
For development purposes, you can use angular's built-in proxy server, but not for production.
Here is a basic nginx config to do this
server {
listen 80;
server_name yourdomain.com; #domain where your angular code is deployed
location /iso-api{
RewriteRule ^/iso-api/(.*)$ /$1 break;
proxy_pass https://thirdpartyapidomain.com; #url of the API you are trying to access
}
location
{
#Your normal angular location
#try_files ...
}
}
This will redirects requests like
http://yourdomain.com/iso-api/countriesList to https://thirdpartyapidomain.com/countriesList;
Since now client and server API calls are on the same domain, you should not have CORS issues
Use this site to resolve the CORS error:
https://cors-anywhere.herokuapp.com/
Use Exemple
https://cors-anywhere.herokuapp.com/https://freegeoip.app/json
this._http.get('https://cors-anywhere.herokuapp.com/https://freegeoip.app/json')
It's just a workaround but it works. Use it even just to understand if the error is related to CORS or something else.
Try the .get call with option withCredentials: true:
return this._http.get<GetStoresResponse>(API.storeUrl, { withCredentials: true }).pipe();
...and/or making sure your browsers are up to date.

Cookies not saved when using npm request library

I have a local environment and I'm trying to login to a service. I'm using the 'request' library in the client and Express and express-session in the service.
I'm using Chrome and when I login to the service I get the following response headers:
FROM: http://app.dev:3000
TO: http://app.dev:4000/login/local
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://app.dev:3000
Vary: Origin, X-HTTP-Method-Override
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
Content-Length: 304
ETag: W/"130-fdQBs605dSVTeEqXEuXrvdcQTLk"
set-cookie: auth=TOKEN; Path=/; Expires=Sun, 25 Jun 2017 01:48:41 GMT
Date: Sat, 24 Jun 2017 13:48:41 GMT
Connection: keep-alive
When I login with Postman the cookie gets stored correctly. Subsequent requests through Postman include the cookie and everything is working fine.
But doing the same request with the npm request library it won't save the cookie and subsequent requests to the backend do not include cookies. Example request to the service after logging in. No cookie sent.
The request library documentation doesn't mention the withCredentials option but setting it to true fixes the issue. The cookie now gets saved and is being sent on subsequent requests.
const requestBase = request.defaults({
baseUrl: 'http://app.dev:4000/',
withCredentials: true,
});

hapi.js Cors Pre-flight not returning Access-Control-Allow-Origin header

I have an ajax file upload using (Dropzone js). which sends a file to my hapi server. I realised the browser sends a PREFLIGHT OPTIONS METHOD. but my hapi server seems not to send the right response headers so i am getting errors on chrome.
here is the error i get on chrome
XMLHttpRequest cannot load http://localhost:3000/uploadbookimg. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
this is the hapi js route handler
server.route({
path: '/uploadbookimg',
method: 'POST',
config: {
cors : true,
payload: {
output: 'stream',
parse: true,
allow: 'multipart/form-data'
},
handler: require('./books/webbookimgupload'),
}
});
In my understanding hapi js should send all cors headers from the Pre-fight (OPTIONS) request.
Cant understand why its is not
Network request /response from chrome
**General**
Request Method:OPTIONS
Status Code:200 OK
Remote Address:127.0.0.1:3000
**Response Headers**
view parsed
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
cache-control: no-cache
vary: accept-encoding
Date: Wed, 27 Apr 2016 07:25:33 GMT
Connection: keep-alive
Transfer-Encoding: chunked
**Request Headers**
view parsed
OPTIONS /uploadbookimg HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36
Access-Control-Request-Headers: accept, cache-control, content-type
Accept: */*
Referer: http://localhost:4200/books/upload
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Thanks in advance
The hapi cors: true is a wildcard rule that allows CORS requests from all domains except for a few cases including when there are additional request headers outside of hapi's default whitelist:
["accept", "authorization", "content-type", "if-none-match", "origin"]
See the cors option section in the API docs under route options:
headers - a strings array of allowed headers ('Access-Control-Allow-Headers'). Defaults to ['Accept', 'Authorization', 'Content-Type', 'If-None-Match'].
additionalHeaders - a strings array of additional headers to headers. Use this to keep the default headers in place.
Your problem is that Dropzone sends a couple of headers along with the file upload that aren't in this list:
x-requested-with (not in your headers above but was sent for me)
cache-control
You have two options to get things working, you need to change something on either the server or the client:
Option 1 - Whitelist the extra headers:
server.route({
config: {
cors: {
origin: ['*'],
additionalHeaders: ['cache-control', 'x-requested-with']
}
},
method: 'POST',
path: '/upload',
handler: function (request, reply) {
...
}
});
Option 2 - Tell dropzone to not send those extra headers
Not possible yet through their config but there's a pending PR to allow it: https://github.com/enyo/dropzone/pull/685
I want to add my 2 cents on this one as the above did not fully resolve the issue in my case.
I started my Hapi-Server at localhost:3300. Then I made a request from localhost:80 to http://localhost:3300/ to test CORS. This lead to chrome still blocking the ressource because it said that
No 'Access-Control-Allow-Origin' header is present on the requested
resource
(which was not true at all).
Then I changed the XHR-Request to fetch the url to a url for which I actually created a route inside HapiJS which - in my case - was http://localhost:3300/api/test. This worked.
To overgo this issue I created a "catch-all" route in HapiJS (to overgo the built-in 404 catch).
const Boom = require('Boom'); //You can require Boom when you have hapi
Route({
method: '*',
path: '/{any*}',
handler: function(request, reply) {
reply(Boom.notFound());
}
})

http.get Parse Error, code: 'HPE_UNEXPECTED_CONTENT_LENGTH'

I have a simple node script to process some data from my home automation API. Everything worked fine till last Node update. Now, with Node version 4.3.0 or 5.6.0, the http module gives me this error:
{ [Error: Parse Error] bytesParsed: 193, code: 'HPE_UNEXPECTED_CONTENT_LENGTH' }
An example of the API call causing the error, it just returns one number (a temperature):
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 5
Content-Type: application/json
Transfer-Encoding: chunked
21.81
And a code to reproduce an error:
const http = require("http");
const url = "http://127.0.0.1:8083/ZWaveAPI/Run/devices[11].instances[2].commandClasses[49].data[1].val.value";
http.get(url, (res) => {
// consume response body
res.resume();
}).on("error", (e) => {
console.log(e);
});
I think that error related to the CVE-2016-2216 Response Splitting Vulnerability, but I tried to run the script with mentioned there --security-revert=CVE-2016-2216 flag and it didn't help. Any ideas?
I found this commit log. The problem seems is Content-Length and Transfer-encoding: chunked headers exist together:
the server is sending
both a Content-Length header and a Transfer-Encoding: chunked
header, which is a violation of the HTTP spec.
As said in the previous answer this is node design as per HTTP standards. i got this issue when I was trying to access REST-API (a content disposition call) in my DEV server from my Angular App running in my local machine. API was not adding these headers Content-Length and Transfer Encoding.
The issue resolved when the app was also deployed to Dev server (Angular App and REST API in same server).
From what I understood, Remove one header if both are being added in API
or Try deploying app in Server.
This is a useful link on this issue - https://github.com/request/request/issues/2091

Categories

Resources