13 August 2012

Nginx post action to trigger successfully download file

As you know nginx is a lightweigh but very powerful http server, and it has a lot of cool features.

Suppose that you have an nginx server hosts some files, and you want to track how many people has successfully download and how many has fails or cancel. This post will show you how to do that with nginx post_action directive.

Requirement :

Let's see the picture below


Topology 

In this LAB, I'll use two servers :
  • Host files server running nginx, IP address = 10.254.10.30 
  • Counting server : host some webservice .php page (running by apache httpd) to count the download session, maybe connect to some database for store the info. IP address = 10.254.10.31 

Steps in detail :

Create some test file on the NginxServer.

NginxServer# cd /usr/share/nginx/html/
NginxServer# dd if=/dev/zero of=file.bin bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 0.113983 seconds, 920 MB/s

On the client, try download the file.

Client# wget http://10.254.10.30/file.bin

http://10.254.10.30/file.bin
Connecting to 10.254.10.30:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [application/octet-stream]
Saving to: `file.bin'
100%[==========================================================>]
104,857,600 54.4M/s in 1.8s
09:35:34 (54.4 MB/s) - `file.bin' saved [104857600/104857600]

Checking the logfile on the NginxServer

NginxServer# tail /var/log/nginx/access.log

10.254.10.29 - - [21/Jun/2012:09:35:31 +0700] "GET /file.bin HTTP/1.1" 200 104857600 "-" "Wget/1.13.4 (linux-gnu)" "-"

Yes, you can see the logfile that client has downloaded the file, but you can not know whether the client successfully or fail or cancel the download because in the logfile there is no entry for that infomation.

Let's add some configuration in the NginxServer :

NginXServer# vim /etc/nginx/nginx.conf

location /
{
 root /usr/share/nginx/html;
 index index.html index.htm;
 post_action /afterdownload;
}

location /afterdownload
{
 proxy_pass http://10.254.10.31/counting.php?FileName=$request&ClientIP=$remote_addr&body_bytes_sent=$body_bytes_sent&status=$request_completion;
 internal;
}

Yes, after finishing a download session (no matter what if successful | fails | user cancel), the nginx server will make a proxy call to some external URL (in this case, i've point it to the CountingServer).
Let's download the file again.

Client# wget http://10.254.10.30/file.bin

http://10.254.10.30/file.bin
Connecting to 10.254.10.30:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [application/octet-stream]
Saving to: `file.bin'
100%[=========================================================>]

104,857,600 52.4M/s in 1.9s
10:14:08 (52.4 MB/s) - `file.bin' saved [104857600/104857600]

Check the CountingServer log.

CountingServer# tail /var/log/httpd/access.log

10.254.10.30 - - [21/Jun/2012:10:14:06 +0700] "GET /counting.php?FileName=GET /file.bin HTTP/1.1&ClientIP=10.254.10.29&body_bytes_sent=104857600&status=OK HTTP/1.0" 200 10 "-" "Wget/1.13.4 (linux-gnu)"

Yeah. The access log is very clearly. The file has been successfully downloaded (status=OK).

Let's download the file again, and cancel it when processing (by pressing Ctrl+c)

Client# wget http://10.254.10.30/file.bin

http://10.254.10.30/file.bin
Connecting to 10.254.10.30:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [application/octet-stream]
Saving to: `file.bin'
63% [=========================================> ] 66,981,354 53.2M/s

Check the log of the CountingServer.

CountingServer# tail /var/log/httpd/access.log

10.254.10.30 - - [21/Jun/2012:10:13:39 +0700] "GET /counting.php?FileName=GET /file.bin HTTP/1.1&ClientIP=10.254.10.29&body_bytes_sent=75427840&status= HTTP/1.0" 200 10 "-" "Wget/1.13.4 (linux-gnu)"

The entry "status= " has been blanked instead of "OK". That mean the progress was terminated when going on (maybe user cancel)

So, by using nginx post_action directive, you can now trigger an action after client finish downloading.