📜 ⬆️ ⬇️

Javascript and nginx = nginScript, and http2 to boot


It was evening, there was nothing to do, but the head did not give rest to the hands and wanted something for the soul ... And for the soul I wanted something new, something unusual.

I, like many of habrovchan, love new items. The release of the new software is like a holiday. New features, new features ... New ways to hammer nails and ride bicycles. New bikes ... In general, you can come up with a bunch of allegories and metaphors. And what am I talking about? Oh yeah, about Nginx, HTTP2 and JavaScript. What are they connected, you ask? And the fact that the latest version of Nginx (1.9.5) added many interesting buns, namely:


Go under the cat, I will tell the details.

Actually, I was interested in these two features. I am an experienced warrior who has switched from lager (a typo on freud - I love lager and dark ale) bendingers to the front-end side. But I continue to follow my favorite tools, including Ngnix.
')

Pro http2


I will not talk much. He works. And the config is easier than for SPDY. Well, or similar. To build a server with HTTP2 support, we add a parameter in the configuration:

--with-http_v2_module 

And that's all. Everything is simple, no patches and third-party libs, just one line in the configuration before building. On Habré you can find information on HTTP2:

  1. Explanation http2
  2. A test version of the HTTP / 2 module for NGINX has been published.

About JavaScript


Oh, this is the most interesting! Frontendors, I hasten to inform you that we have a new dialect of JavaScript (well, we are no stranger to if cho) - this is nginScript (endzhin script). Hooray! I always knew that if a programmer had a microscope, then everything around seemed like nails. Joke, dear programmers, joke.

JavaScript scripts can be used directly in the configuration file (!) To define advanced query processing logic. For configuration formation, for dynamic response generation. You can also make a modification of the request and response. And, you can quickly create stubs with solving problems in web applications (aka "crutches" or temporarily do so, and then redo it as it should). This is just kruatoshka krutatenyushka, I tell you!

The script itself is launched via the js_run directive and allows it directly on the server side (what am I carrying?) ... No, right in the server itself, perform many low-level operations with the request, without having to write a separate module in C / Lua or what else they write and decide such tasks.

To run the script uses its own engine njs. For this, the Nginx development team has implemented its version of the virtual machine under a trimmed subset of the JavaScript language. Actually, this language was called nginScript, so as not to be confused with JavaScript, because, nevertheless, this is a subset. What's interesting: for each request, a separate virtual machine is started, which allows you to do without the garbage collector. JavaScript is selected as the most popular programming language. Lua was a good contender, but it is not as widespread in web development circles. The need to create your own JavaScript virtual machine is due to the fact that existing engines are optimized to work in the browser, while for Nginx you need not just a server implementation, but integrated into the engine. In general, the developers did not pull the full V8. Therefore, it is JavaScript, but it is necessary to write as under IE6, without showing off. Yet this config, if that.

NginScript has a virtual machine and a compiler byte code with quick start and shutdown. Blocking operations, such as HTTP subqueries, can be suspended and resumed by analogy with other blocking operations in JS.

Syntax instructions have been added to the Nginx config description language, which allows embedding blocks of JS code directly into the configuration file. Such blocks are executed as HTTP transactions are processed and allow for each request to perform such operations as adjusting the internal parameters of nginx, creating complex conditions, changing the request or response.

Using nginScript, you can describe configs that, without writing additional extensions and modules, can dynamically block malicious requests that exploit vulnerabilities in web applications or limit the intensity of certain requests. You can also implement flexible traffic redirection rules that use information from the request and not only.

And you can also make hot crutches! We can correct errors in web applications, change business logic, distribute requests to several servers with the subsequent aggregation of responses from them and much more ... And all this is right in the config. And all this in the familiar language that we love.

So, a lot of beeches, let's move on to the installation and examples.

Installation


If no mercury is set, we set. And further according to the instructions:

 # Obtain the latest source for NGINX from http://nginx.org/en/download.html $ wget http://nginx.org/download/nginx-1.9.5.tar.gz $ tar -xzvf nginx-1.9.5.tar.gz # Obtain the development sources for nginScript $ hg clone http://hg.nginx.org/njs # Build and install NGINX $ cd nginx-1.9.5 $ ./configure \ --sbin-path=/usr/sbin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --pid-path=/var/run/nginx.pid \ --lock-path=/var/run/nginx.lock \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --user=www \ --group=www \ --with-ipv6 \ --with-pcre-jit \ --with-http_gzip_static_module \ --with-http_ssl_module \ --with-http_v2_module \ --add-module=../njs/nginx \ \ $ make -j2 && make install 

nginScript aka javascript


We can predefine variables with the results of the calculation via the js_set directive:

 js_set $js_txt " var m = 'Hello '; m += 'world!'; m; "; server { listen :443 ssl http2; server_name edu.tutu.ru; set $sname edu.tutu.ru; set $root "/www/sites/$sname/www/public"; ssl_certificate /etc/nginx/ssl/edu.tutu.ru.pem; ssl_certificate_key /etc/nginx/ssl/edu.tutu.ru.key; include base.conf; location /helloworld { add_header Content-Type text/plain; return 200 $js_txt; } } 

As you can see, an unusual instruction is used as the return value. It is strange, why not make the word return. Directly unexpected and unusual. But oh well, have done so.

As I understand the directive can be installed outside the server blocks. Otherwise, the parser swears.

You can immediately generate content from the config and send it to the browser:

 location /helloworld { js_run " var res; res = $r.response; res.contentType = 'text/plain'; res.status = 200; res.sendHeader(); res.send('Hello, world!'); res.finish(); "; } 

Let's do http_dump, m?

 js_set $http_dump " var a, s, h; s = 'Request summary\n\n'; s += 'Method: ' + $r.method + '\n'; s += 'HTTP version: ' + $r.httpVersion + '\n'; s += 'Host: ' + $r.headers.host + '\n'; s += 'Remote Address: ' + $r.remoteAddress + '\n'; s += 'URI: ' + $r.uri + '\n'; s += 'Headers:\n'; for (h in $r.headers) s += ' header \"' + h + '\" is \"' + $r.headers[h] + '\"\n'; s += 'Args:\n'; for (a in $r.args) s += ' arg \"' + a + '\" is \"' + $r.args[a] + '\"\n'; s; "; server { listen :443 ssl http2; server_name edu.tutu.ru; set $sname edu.tutu.ru; set $root "/www/sites/$sname/www/public"; ssl_certificate /etc/nginx/ssl/edu.tutu.ru.pem; ssl_certificate_key /etc/nginx/ssl/edu.tutu.ru.key; location /js/httpdump { add_header Content-Type text/plain; return 200 $js_summary; } } 

And let's write a service for calculating Fibonacci numbers


If there is a microscope, then why don't they hammer a nail? When asked why, a real programmer / scientist / inventor will always answer: because I can do it! Yes, I can write such a service without leaving the Nginx config, without installing Nodejs, PHP or Ruby. I can do all this inside the server! Yes!

 location /js/getfib { js_run " function fib(n) { var prev = 1, curr = 1, newc, i; if (n < 2) return n; for (i = 3; i <= n; i++) { newc = prev + curr; prev = curr; curr = newc; } return curr; } var n = +$r.args['n'], txt = 'Fibonacci( ' + n + ' ) = ' + fib(n), res = $r.response; res.contentType = 'text/plain'; res.status = 200; res.sendHeader(); res.send(txt); res.send('\n'); res.finish(); "; } 

I wanted to write instead:

 newc = prev + curr; prev = curr; curr = newc; 

unstructured code:

 [ prev, curr ] = [ curr, prev + $curr ]; 


But nginScript doesn't know anything about ES2015 / ES6. Then I wrote this:

 prev = [ curr, prev += curr ][0]; 

And here, too, was Fail. It turns out that writing is also impossible. So, friends, not everything is possible. A kind of IE5 is obtained. But overall I liked it.
Good to you, what do you have there now.

Related Links




UPD

An example of binding upstream and dynamic routing


 upstream my_upstream0 { server server1.example.com; server server2.example.com; } upstream my_upstream1 { server server3.example.com; server server4.example.com; } js_set $my_upstream " var s, upstream, upstream_num; upstream = $r.args.upstream; // convert upstream number to integer upstream_num = +upstream | 0; if (upstream_num < 0 || upstream_num > 1) { upstream_num = 0; } s = 'my_upstream' + upstream_num; s; "; server { listen 80; location / { proxy_set_header Host $host; proxy_pass http://$my_upstream; } } 

Source: https://habr.com/ru/post/267955/


All Articles