Request: noproxy configuration

Like with npm and for the same reasons, it would be a great idea to have a noproxy configuration in request.
So here is the pull request!

if(self.noproxy) {
  if(typeof self.noproxy == 'string') {
    if(self.noproxy.search(self.uri.hostname) !== -1) {
      delete self.proxy
    }
  }
}

Really simple. If the hostname is in the noproxy string, we delete the proxy parameter so that it won’t be used.

And the test which validate the modification:

/*
** Test noproxy configuration.
**
** We create a server and a proxy.
** Server listens on localhost:80.
** Proxy listens on localhost:8080.
** The proxy redirects all requests to /proxy on the server.
** On the server, /proxy sends "proxy" .
** When server is directly requested, it answers with "noproxy" .
**
**
** So we perform 2 tests, both with proxy equal to "http://localhost:8080".
** -A test is performed with noproxy equal to "null". In this case,
** the server responds with "proxy" because the proxy is used.
** -In the other test, noproxy equal "localhost, example.com".
** Since localhost is part of noproxy, request is made directly
** to the server and proxy is ignored.
*/

var assert = require("assert")
  , http = require('http')
  , request = require('../main.js')
  //We create a server and a proxy.
  , server = http.createServer(function(req, res){
      res.statusCode = 200
      if(req.url == '/proxy') {
        res.end('proxy')
      } else {
        res.end('noproxy')
      }
    })
  , proxy = http.createServer(function (req, res) {
      res.statusCode = 200
      var url = 'http://localhost:80/proxy'
      var x = request(url)
      req.pipe(x)
      x.pipe(res)
    })
    ;

//Launch server and proxy
var initialize = function (cb) {
  server.listen(80, 'localhost', function () {
    proxy.listen(8080, 'localhost', cb)
  })
}

//Tests
initialize(function () {
  //Checking the route for server and proxy
  request.get("http://localhost:80/test", function (err, res, body) {
    assert.equal(res.statusCode, 200)
    request.get("http://localhost:80/proxy", function (err, res2, body) {
      assert.equal(res2.statusCode, 200)
      request.get("http://localhost:8080/test", function (err, res3, body) {
        assert.equal(res3.statusCode, 200)
        makeNoProxyTest(function () {
          makeProxyTest(function () {
            closeServer(server)
            closeServer(proxy)
          })
        })
      })
    })
  })
})

//Request with noproxy
var makeNoProxyTest = function (cb) {
  request ({
    url: 'http://localhost:80/test',
    proxy: 'http://localhost:8080',
    noproxy: 'localhost, example.com'
  }, function (err, res, body) {
    assert.equal(body, 'noproxy')
    cb()
  })
}

//Request with proxy
var makeProxyTest = function (cb) {
  request ({
    url: 'http://localhost:80/test',
    proxy: 'http://localhost:8080',
    noproxy: 'null'
  }, function (err, res, body) {
    assert.equal(body, 'proxy')
    cb()
  })
}

var closeServer = function (s) {
  s.close()
}

Placer le focus à la fin d’un champ / Place focus at the end of a field

function setFocusBack (element) {
  var tmp = element.val();
  element.focus().val('');
  element.val(tmp);
}

element est une sélection JQuery comme par exemple: $(‘.text’).
Cette fonction permet donc de remettre facilement le focus à la fin d’un champ d’input (par exemple).

Where element is a JQuery selector like for instance $(‘.text’).
This function allows us to easily set the focus back at the end of an input field (for instance).

Html:

<input type="text" placeholder="ER" class="text"/>

File upload with Ajax and Cross-domain

I’ve recently tried to upload a file from a client to a server and faced the problem of cross-domain. Indeed, uploading is done with ajax, to be able to analyze the response. So, I had to solve 2 problems: uploading with ajax and cross-domain.

Concerning cross-domain, I’ve found many different solutions but none of them really fit my need since I needed to add informations in the header. (I think there were other reasons, but cannot remember). I find it easier to make a two step upload. First, I upload the file to my simple PushState server, then the server upload the file to the other website. This server is built using NodeJs, express and request. Upload is made with request and its form parameter which allows us to do multipart/form-data.
Here is the server:

var express = require('express');
var request = require('request');
var fs = require('fs');
var app = express();

app.use(express.logger());
app.use(express.bodyParser({uploadDir:'./tmp'}));
app.use(app.router);
app.use(express.static('./public'));
app.use(function(req, res) {
  fs.createReadStream('./public/index.html').pipe(res);
});

app.post('/upload', function(req, res, next) {
  //Configure the request
  var opts = {
    url: "http://your/url",
    method: "POST",
    headers: {
      login: "yourLogin",
      password: "yourPassword"
    }
  };

  var x = request(opts);
  var form = x.form();

  //Optionnal: Add a name and a type to form
  var fileName = req.files.file.name.split('.');
  form.append('name', fileName[0]);
  form.append('type', fileName[fileName.length - 1]);

  //Add file to the request
  form.append('file', fs.createReadStream(req.files.file.path));

  //Pipe response from website to the client
  x.pipe(res);
});

app.listen(4242, function() {
  console.log('Server running!');
});

Uploading with ajax is done thank to jquery.iframe-transport (just add it in your code).
Concerning ajax, code is really simple:

$.ajax({
  url: "http://localhost:4242/upload",
  type: 'POST',
  files: $('.fileUpload'),
  iframe: true,
  success: function(data, textStatus, jqXHR) {
    //Do whatever you want with the response
  },
  error: function(err) {
    console.error(err);
    console.log("Error while uploading the document. :/");
  }
});

The html behind:

<form enctype="multipart/form-data">
  <input class='fileUpload' type="file" name="file"/>
</form>

In this case, I listen for the event change input.fileUpload which indicates that a file has been chosen and then, call a function executing the ajax part. It would also be possible to react on click on a button.

Other solutions concerning cross-domain:                                                      http://stackoverflow.com/questions/3076414/ways-to-circumvent-the-same-origin-policy                                                                                  https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads

NPM: noproxy Configuration

For security reasons, every firms are generally using a proxy to manage their internet connection. Coding behind a proxy is fine. Most softwares are able to deal with it. You just have to set it in the environment variable of your GNU/Linux OS or directly in the software.

But there is one problem. Because every request must go through the proxy, it’s impossible to request url based in the internal network. There is only one solution: disable proxy, make request, enable proxy. If you are using npm until now, that’s what you have to do.

In order to make this process easier, I’ve made a pull request which add a noproxy configuration. When npm fetches a package from a given url, the hostname is compared with noproxy configuration. If there is a match, the request is made without proxy, if not proxy is used.

The noproxy configuration looks for a variable named « noproxy » in npm configuration.
« noproxy » is a string containing hostnames. So, this list of hostnames will not ever go through a proxy.
Code concerned:

var proxy = null
if(npm.config.get("noproxy").search(remote.hostname) === -1) {
  if (remote.protocol !== "https:" || 
      !(proxy = npm.config.get("https-proxy"))) {
    proxy = npm.config.get("proxy")
  }
}

var opts = { url: remote
          , proxy: proxy
          , strictSSL: npm.config.get("strict-ssl")
          , ca: remote.host === regHost ? 
                                npm.config.get("ca") : undefined
          , headers: { "user-agent": npm.config.get("user-agent") }}

var req = request(opts)

At the moment, I’m still waiting for Isaacs to add the pull request in npm.
I hope it will be added soon.

Update:                                                                                                                                     Isaacs has pointed out that it’s good for the npm bit but some modifications are still needed in npm-registry-client and npmconf . So here are new additions:

  • npmconf:
 , "noproxy" : process.env.NO_PROXY || process.env.no_proxy ||  "null"
 , "no-proxy" : ["null", String]
  • npm-registry-client:
  var p = this.conf.get('proxy')
  var sp = this.conf.get('https-proxy') || p
  var np = this.conf.get('noproxy')

  if(np.search(remote.hostname) === -1) {
    opts.proxy = remote.protocol === "https:" ? sp : p
  }

I hope everything is now in order so that noproxy configuration can be added to npm :).