I am making an express.js server to store pictures.
const express = require('express');
const app = express();
app.get('/*', (request, response) =>
{
response.sendFile(__dirname + '/data' + request.path);
});
app.listen(9999);
console.log('Server started on port 9999');
And I have a problem. If I type http://127.0.0.1:9999/vehicles/boats/dinghy.png into browser, I get a picture, but when I type https://127.0.0.1:9999/main/avatar.png I get This site can’t provide a secure connection 127.0.0.1 sent an invalid response. Both files do exist, but one of them is sent correctly, but another one gives an error. What can it be caused by?
Your second request is sent via https. As you're not providing a valid certificate for localhost at your express app, the browser will give you a hint about this.
Related
It seems that express default behaviour is to normalize URLs containing up directory (/../)
For the code below, if I request a URL like this
http://localhost:8080/foo/../../bar
the request gets redirected to
http://localhost:8080/bar
I couldn't find any detailed documentation on this behavior.
my questions are:
is it a guaranteed behavior
in case I am not serving from a file system is there a way to preserve the original URL "path" in case i am using other processing?
by
const express = require("express")
const app=express()
app.get("/*", (req,res) => {
console.log("url:",req.url);
console.log("path:",req.path);
res.send('echo for url='+req.url+'; path='+req.path')
}
const port=8080;
app.listen(port,() =>{
console.log(`listening on port ${port}`);
});
The request is not redirected, but rather the client rebuilds the URL before making the request
>curl -v http://localhost:8080/foo/../../bar
* Rebuilt URL to: http://localhost:8080/bar
Therefore the server never sees the "original URL path".
This URL rebuilding is part of the resolution process. See also https://url.spec.whatwg.org/#concept-basic-url-parser.
A malicious client (e.g., a telnet client) could, however, send an HTTP request with "unresolved" URL. The following middleware demonstrates how to rebuild the URL on the server:
function(req, res) {
res.json({path: req.path,
rebuilt_path: new URL("s://" + req.path).pathname});
}
The malicious request
GET /foo/../../bar HTTP/1.1
Host: localhost:8080
then returns
{"path": "/foo/../../bar", "rebuilt_path": "/bar"}
(Things get more complicated if req.baseUrl is also involved.)
const express = require("express");
const app = express();
const https = require("https");
app.get("/", function (req, res){
var url = "https://***";
https.get(url, function(response){
console.log(response);
});
res.send("server running");
});
Express is really just a layer on top of http.
I reckon those following links might help you out, this question has been asked.
what's the technical difference between express and http, and connect for that matter
Difference between a server with http.createServer and a server using express in node js
app.get() registers a listener for a specific INCOMING http request path on a local Express server.
https.get() makes an OUTBOUND https request TO some other https server to fetch content from that other server.
And, obviously, the https.get() is using https, not http. The app.get() could be listening for either - it depends upon how the server it is part of is started (as an http server or an https server) which the code you have in your question does not show.
I have a node express server responding to http traffic:
const http = require("http");
const express = require("express");
const app = express();
const server = http.createServer(app);
app.use(function(req,res,next){
console.log(`logging: req: ${util.inspect(req)}`);
next();
});
and all that works fine. I'd like to have a program on my node server inject emulated http traffic into the express stack, without a network connection. I can't just magic up a (req,res) pair and call a middleware function like the one in app.use above, because I don't have a next to give it, and my req and res will not be the ones next passes on to the next middleware in the stack.
Edit: What I actually have is a websocket connection sending data packets of a different format, different data contents from http traffic that can also carry the same information. I can take those websocket packets and build from those a request that is in the same format that the http traffic uses. I would like to pass that transformed request through the express http middleware stack and have it processed in the same way. Going all the way back to create an http request having just dealt with a ws request seems a bit far.
What's the simplest way to emulate some traffic, please? Can I call a function on app? Call some express middleware, or write a middleware of my own to inject traffic? Call a function on server?
Thanks!
Emulation traffic by calling some Express.js internal functions isn't the right way. Much easier is to trigger the server by HTTP request from the same process
const http = require('http');
const util = require('util');
const express = require('express');
const app = express();
const server = http.createServer(app);
app.use(function(req, res, next) {
console.log(`logging: req: ${util.inspect(req)}`);
next();
});
const port = 8081;
server.listen(port);
http.request({ port }).end();
From your question
I'd like to have a program on my node server inject emulated http traffic into the express stack, without a network connection
Can you clarify, why without a network connection?
A few things:
You need to make an endpoint
You need to host your server somewhere
You need something to send requests to your server
Express provides you a way to receive requests (req, res) (might be from a browser, might not be), perform some operations, and return responses (req, res) to the requester.
The expression
app.use(function(req,res,next){
console.log(`logging: req: ${util.inspect(req)}`);
next();
});
is actually a middleware function. This will take every request to your server and change the request object created by express into a string, and print it in your server log.
If you want a testable endpoint, you would add this to the bottom of the snippet you posted
app.get('/test', function (req, res) {
res.json({success:true})
})
This tells your app to allow GET requests at the endpoint /test
Next you're going to need to host your express server somewhere you can send requests to it. Your local machine (localhost) is a good place to do that. That way, you don't need an internet connection.
Pick a port you want to host the server on, and then it will be reachable at http://localhost:<Your Port>.
Something like this will host a server on http://localhost:3000. Add this below the route we declared above:
server.listen(3000, function() {
console.log('Server running on port 3000');
});
Finally, you'll need a way to send requests to the server on localhost. Postman is a great tool for testing express routes.
I would suggest installing Postman and using that to emulate http traffic.
Once your server is running, open postman and send a GET request to your server by entering the server address and port, and hitting the blue send button (You'll be sending the request to http://localhost:3000/test).
Here's an image of what postman should look like if all goes well
You should also see your middleware fire and print out the request object in your terminal.
Good Luck!
I have a web application where the front-end is done with React (create-react-app) and it is deployed on Heroku. The back-end is done with node.js/express and it runs on an Amazon EC2.
I don't have any problem getting the app to work when I deploy the front-end on localhost or on Heroku if I access it with HTTP as http://myapp.heroku.com. The problem arises when I access it with HTTPS (which is the default on Heroku) as https://myapp.heroku.com. When I do so and send a request to the node.js server on the Amazon EC2, I get the following error:
Error: Network Error
Stack trace:
createError#https://myapp.herokuapp.com/static/js/bundle.js:1555:15
handleError#https://myapp.herokuapp.com/static/js/bundle.js:1091:14
Here is the part in the front-end which send the request to the node.js server:
_deflateAscii(valueAscii){
axios.post('//My-EC2-Instance-Here.compute.amazonaws.com:80/deflate/ascii', {inflatedAscii: valueAscii}).then(res => {
this.setState(
{
inflatedAscii: valueAscii,
inflatedHex: res.data.inflatedHex,
deflatedBase64: res.data.deflatedBase64,
deflatedHex: res.data.deflatedHex
},
this._setTextBoxesValues
);
}).catch((err) => {
console.log(err)});
}
Here are the modules I use on the server-side:
const express = require('express');
const cors = require('cors');
const http = require('http');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cors());
And the part handling coming request from the front-end:
app.post('/deflate/ascii', function(req, res){
try{
console.log('request received');
var inflatedHexValue = convert.asciiToHex(req.body.inflatedAscii);
var deflatedBase64Value = deflate.asciiToBase64(req.body.inflatedAscii);
var deflatedHexValue = deflate.asciiToHex(req.body.inflatedAscii);
}catch(err){
console.log(err);
res.status(500).send(err);
}
response = {
deflatedBase64: deflatedBase64Value,
deflatedHex: deflatedHexValue,
inflatedHex: inflatedHexValue
};
res.end(JSON.stringify(response));
console.log('response sent');
});
When I get the Network Error on the front-end, the node.js server does not receive the request, but I have done some diagnostics with Wireshark and there is and handshake with the EC2 server, but the traffic ends there without any HTTP traffic:
TCP-traffic between https://myapp.heroku.com/ and My-EC2-Instance-Here.compute.amazonaws.com
Do I need SSL on the backend if the frontend is HTTPS? From this post I understood that it can also do without Do we need ssl certificate for both front end and backend?. This is just a course project anyway and there is only meaningless strings going back and forth.
When you visit your site over https in a browser, you need to disable blocking of mixed content (http and https). As a result your browser classifies the connection as not secure.
So yes it would be good to use SSL/TSL both for backend and frontend.
Alos did you try to use
res.json(response);
res.status(200).end();
or set the headers to application/json?
I recommend to put your res calls into the try catch block, because your res.end will be executed anyway.
I'm trying to restrict the origin of CORS requests to one specific domain per route using the express.js CORS package like so:
const express = require('express');
const cors = require('cors');
const port = process.env.PORT || 3000;
let app = express();
app.get('/', cors({origin: 'http://example.com'}), (req, res, next) => {
res.sendStatus(200);
});
app.post('/', cors({origin: 'http://whatever.com'}) (req, res, next) => {
res.sendStatus(200);
});
app.listen(port, () => {
console.log(`Started on port ${port}`);
});
This doesn't seem to have any effect, however, as I'm able to GET and POST from any domain. I then tried instead to restrict all routes to one single origin using the following, but met the same results:
app.use(cors({origin: 'http://example.com'}));
I'm experiencing this both in my dev environment on localhost and my production environment on Heroku. Any idea what I'm missing?
If your server is sending an Access-Control-Allow-Origin: http://example.com response header, then you actually already have it configured correctly.
It’s expected behavior for the server to return a 200 response no matter what origin you make the request from—even for those from an origin other than the configured http://example.com
The CORS settings don’t cause the server to block requests from any clients.
Instead, if the server responds with Access-Control-Allow-Origin: http://example.com to a client request from JavaScript code in a web app that’s not running at http://example.com, then the browser blocks that JavaScript code from being able to access the response.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS gives more details.
Basically the way it works is that from the server side, no behavior changes other than the difference in what response headers it sends. So the server will receive the request just as it otherwise would, and will send the response just as it otherwise would.
And then the browser will receive the response just as it otherwise would. You will be able to see the response in your browser devtools and examine it there. But that does not mean the browser will expose the response to your client-side JavaScript code.
Instead, the browser checks the value of the Access-Control-Allow-Origin response header from the server and will only expose the response cross-origin to your origin if the server says it should be allowed to: Your browser checks the value of the Access-Control-Allow-Origin against your actual origin, and if it either matches exactly or the value is * to allow any origin, only then does the browser allow your client-side JavaScript code to access the response.