forked from masterzen/nginx-upload-progress-module
-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
329 lines (259 loc) · 11.5 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
Nginx Upload Progress Module
============================
Introduction
============
nginx_uploadprogress_module is an implementation of an upload progress system, that monitors
RFC1867 POST upload as they are transmitted to upstream servers.
It works by tracking the uploads proxied by Nginx to upstream servers without
analysing the uploaded content and offers a web API to report upload progress in Javscript, Json or any
other format (through the help of templates).
It works because Nginx acts as an accelerator of an upstream server, storing uploaded POST content
on disk, before transmitting it to the upstream server. Each individual POST upload request
should contain a progress unique identifier.
This module is Copyright (c) 2007-2012 Brice Figureau, and is licensed under the BSD license (see LICENSE).
* rbtree and shm_zone code is based on Igor Sysoev limit_zone Nginx module.
* expire header code is based on Igor Sysoev header_filter Nginx module.
The JSON idea and the mechanism idea are based on Lighttpd mod_uploadprogress:
http://blog.lighttpd.net/articles/2006/08/01/mod_uploadprogress-is-back
WARNING:
* when compiled with --with-debug, this module will produce high number of log messages.
INCOMPATIBLE CHANGES
====================
v0.9.0:
JSONP is now the default output of the progress probes. If you rely on this module serving
the deprecated java output use:
upload_progress_java_output
in the progress probe location.
Installation
============
nginx_uploadprogress_module has been tested with Nginx 0.6.x, 0.7.x, 0.8.x and 1.0.x.
Download the Nginx sources from http://nginx.net/ and unpack it.
To build Nginx, change to the directory which contains the Nginx
sources, and run the configuration script making sure to add the path
to the nginx_uploadprogress_module sources using the --add-module option: ::
$ ./configure --add-module=/path/to/nginx_uploadprogress_module/
Now you can build and install the software:
$ make
and as root:
$ make install
Configuration
=============
Each upload request should be assigned a unique identifier. This unique identifier will be used
to store the request and reference it to report.
This identifier can be transmitted either as a GET argument or as an HTTP header whose name is X-Progress-ID.
upload_progress
+++++++++++++++
:Syntax: upload_progress <zone_name> <zone_size>
:Default: none
:Context: http
:Description:
This directive enables the upload progress module and reserve <zone_size> bytes to the <zone_name> which
will be used to store the per-connection tracking information.
track_uploads
+++++++++++++
:Syntax: track_uploads <zone_name> <timeout>
:Default: none
:Context: location
:Description:
This directive enables tracking uploads for the current location. Each POST landing in this location will register
the request in the <zone_name> upload progress tracker.
Since Nginx doesn't support yet RFC 1867 upload, the location must be a proxy_pass or fastcgi location.
The POST _must_ have a query parameter called X-Progress-ID (or an HTTP header of the same name) whose value is the
unique identifier used to get progress information. If the POST has no such information, the upload will not be tracked.
The tracked connections are kept at most <timeout> seconds after they have been finished to be able to serve
useful information to upload progress probes.
WARNING: this directive must be the last directive of the location. It must be in a proxy_pass or
fastcgi_pass location.
report_uploads
++++++++++++++
:Syntax: report_uploads <zone_name>
:Default: none
:Context: location
:Description:
This directive allows a location to report the upload progress that is tracked by track_uploads for <zone_name>.
The returned document is a Javascript text with the possible 4 results by default:
* the upload request hasn't been registered yet or is unknown:
new Object({ 'state' : 'starting' })
* the upload request has ended:
new Object({ 'state' : 'done' })
* the upload request generated an HTTP error
new Object({ 'state' : 'error', 'status' : <error code> })
one error code that can be of use to track for the client is 413 (request entity too large).
* the upload request is in progress:
new Object({ 'state' : 'uploading', 'received' : <size_received>, 'size' : <total_size>})
It is possible to return pure json instead of this javascript (see upload_progress_json_output).
It is also possible to configure completely the response format with the directive:
upload_progress_template
The HTTP request to this location must have a X-Progress-ID parameter or HTTP header containing a valid
unique identifier of an in progress upload.
upload_progress_content_type
++++++++++++++++++++++++++++
:Syntax: upload_progress_content_type <content_type>
:Default: text/javascript
:Context: location
:Description:
This directive allows to change the upload progress probe response content-type.
upload_progress_header
++++++++++++++++++++++
:Syntax: upload_progress_header <progress-id>
:Default: X-Progress-ID
:Context: location
:Description:
This directive allows to change the header name of the progress ID.
upload_progress_jsonp_parameter
++++++++++++++++++++++
:Syntax: upload_progress_jsonp_parameter <callback_parameter>
:Default: callback
:Context: location
:Description:
This directive allows to change the name of the GET parameter with the jsonp callback name.
upload_progress_java_output
+++++++++++++++++++++++++++
:Syntax: upload_progress_java_output
:Default: N/A
:Context: location
:Description:
This directive sets everything to output as eval() javascript compatible code.
upload_progress_json_output
+++++++++++++++++++++++++++
:Syntax: upload_progress_json_output
:Default: N/A
:Context: location
:Description:
This directive sets everything to output as pure json.
upload_progress_jsonp_output
++++++++++++++++++++++++++++
:Syntax: upload_progress_jsonp_output
:Default: N/A
:Context: location
:Description:
This directive sets everything to output as jsonp (like json output, but with callback).
upload_progress_template
++++++++++++++++++++++++
:Syntax: upload_progress_template <state> <template>
:Default: none
:Context: location
:Description:
This directive can be used to install a progress response template.
The available list of state is:
* starting
* uploading
* error
* done
Nginx will replace the value of the following variables with their respective
value for the upload:
* $uploadprogress_length: total size of the upload
* $uploadprogress_received: what the server has received so far
* $uploadprogress_status: error code in case of HTTP error
* $uploadprogress_callback: jsonp callback name if provided as a GET query parameter with name 'callback'
For instance to return XML (instead of the default Javascript or json):
upload_progress_content_type 'text/xml';
upload_progress_template starting '<upload><state>starting</state></upload>';
upload_progress_template uploading '<upload><state>uploading</state><size>$uploadprogress_length</size><uploaded>$uploadprogress_received</uploaded></upload>';
upload_progress_template done '<upload><state>done</state></upload>';
upload_progress_template error '<upload><state>error</state><code>$uploadprogress_status</code></upload>';
Example of jsonp response:
upload_progress_template starting "$uploadprogress_callback({ \"state\" : \"starting\"});";
upload_progress_template error "$uploadprogress_callback({ \"state\" : \"error\", \"status\" : $uploadprogress_status });";
upload_progress_template done "$uploadprogress_callback({ \"state\" : \"done\"});";
upload_progress_template uploading "$uploadprogress_callback({ \"state\" : \"uploading\", \"received\" : $uploadprogress_received, \"size\" : $uploadprogress_length });";
Configuration Example:
+++++++++++++++++++++
http {
# reserve 1MB under the name 'proxied' to track uploads
upload_progress proxied 1m;
server {
listen 127.0.0.1 default;
server_name _ *;
root /path/to/root;
location / {
# proxy to upstream server
proxy_pass http://127.0.0.1;
proxy_redirect default;
# track uploads in the 'proxied' zone
# remember connections for 30s after they finished
track_uploads proxied 30s;
}
location ^~ /progress {
# report uploads tracked in the 'proxied' zone
report_uploads proxied;
}
}
Usage Example
=============
(based on Lighttd mod_uploadprogress module example):
First we need a upload form:
<form id="upload" enctype="multipart/form-data"
action="/upload.php" method="post"
onsubmit="openProgressBar(); return true;">
<input type="hidden" name="MAX_FILE_SIZE" value="30000000" />
<input name="userfile" type="file" label="fileupload" />
<input type="submit" value="Send File" />
</form>
And a progress bar to visualize the progress:
<div>
<div id="progress" style="width: 400px; border: 1px solid black">
<div id="progressbar"
style="width: 1px; background-color: black; border: 1px solid white">
</div>
</div>
<div id="tp">(progress)</div>
</div>
Then we need to generate the Unique Identifier and launch the upload on submit
action. This also will start the ajax progress report mechanism.
interval = null;
function openProgressBar() {
/* generate random progress-id */
uuid = "";
for (i = 0; i < 32; i++) {
uuid += Math.floor(Math.random() * 16).toString(16);
}
/* patch the form-action tag to include the progress-id */
document.getElementById("upload").action="/upload.php?X-Progress-ID=" + uuid;
/* call the progress-updater every 1000ms */
interval = window.setInterval(
function () {
fetch(uuid);
},
1000
);
}
function fetch(uuid) {
req = new XMLHttpRequest();
req.open("GET", "/progress", 1);
req.setRequestHeader("X-Progress-ID", uuid);
req.onreadystatechange = function () {
if (req.readyState == 4) {
if (req.status == 200) {
/* poor-man JSON parser */
var upload = eval(req.responseText);
document.getElementById('tp').innerHTML = upload.state;
/* change the width if the inner progress-bar */
if (upload.state == 'done' || upload.state == 'uploading') {
bar = document.getElementById('progressbar');
w = 400 * upload.received / upload.size;
bar.style.width = w + 'px';
}
/* we are done, stop the interval */
if (upload.state == 'done') {
window.clearTimeout(interval);
}
}
}
}
req.send(null);
}
Companion Software
==================
This software can also work with Valery Kholodkov' Nginx Upload Module:
http://www.grid.net.ru/nginx/upload.en.html
You can also use the following javascript libraries client side:
http://drogomir.com/blog/2008/6/30/upload-progress-script-with-safari-support
Note that when using jQuery AJAX for progress monitoring, such as:
https://github.com/drogus/jquery-upload-progress
you should be sure to set a upload_progress template parameter:
upload_progress_json_output
or
upload_progress_jsonp_output
depending on your jQuery AJAX dataType setting.