2
2
var common = require ( '../common' ) ;
3
3
var assert = require ( 'assert' ) ;
4
4
5
+ // Here we are testing the HTTP server module's flood prevention mechanism.
6
+ // When writeable.write returns false (ie the underlying send() indicated the
7
+ // native buffer is full), the HTTP server cork()s the readable part of the
8
+ // stream. This means that new requests will not be read (however request which
9
+ // have already been read, but are awaiting processing will still be
10
+ // processed).
11
+
12
+ // Normally when the writable stream emits a 'drain' event, the server then
13
+ // uncorks the readable stream, although we arent testing that part here.
14
+
5
15
switch ( process . argv [ 2 ] ) {
6
16
case undefined :
7
17
return parent ( ) ;
@@ -18,22 +28,31 @@ function parent() {
18
28
var childClosed = false ;
19
29
var requests = 0 ;
20
30
var connections = 0 ;
31
+ var backloggedReqs = 0 ;
21
32
22
33
var server = http . createServer ( function ( req , res ) {
23
34
requests ++ ;
24
35
res . setHeader ( 'content-length' , bigResponse . length ) ;
25
- res . end ( bigResponse ) ;
36
+ if ( ! res . write ( bigResponse ) ) {
37
+ if ( backloggedReqs == 0 ) {
38
+ // Once the native buffer fills (ie write() returns false), the flood
39
+ // prevention should kick in.
40
+ // This means the stream should emit no more 'data' events. However we
41
+ // may still be asked to process more requests if they were read before
42
+ // mechanism activated.
43
+ req . socket . on ( 'data' , function ( ) { assert ( false ) ; } ) ;
44
+ }
45
+ backloggedReqs ++ ;
46
+ }
47
+ res . end ( ) ;
26
48
} ) ;
27
49
28
50
server . on ( 'connection' , function ( conn ) {
29
51
connections ++ ;
30
52
} ) ;
31
53
32
- // kill the connection after a bit, verifying that the
33
- // flood of requests was eventually halted.
34
54
server . setTimeout ( 200 , function ( conn ) {
35
55
gotTimeout = true ;
36
- conn . destroy ( ) ;
37
56
} ) ;
38
57
39
58
server . listen ( common . PORT , function ( ) {
@@ -53,17 +72,16 @@ function parent() {
53
72
assert . equal ( connections , 1 ) ;
54
73
// The number of requests we end up processing before the outgoing
55
74
// connection backs up and requires a drain is implementation-dependent.
56
- // We can safely assume is more than 250.
57
75
console . log ( 'server got %d requests' , requests ) ;
58
- assert ( requests >= 250 ) ;
76
+ console . log ( 'server sent %d backlogged requests' , backloggedReqs ) ;
77
+
59
78
console . log ( 'ok' ) ;
60
79
} ) ;
61
80
}
62
81
63
82
function child ( ) {
64
83
var net = require ( 'net' ) ;
65
84
66
- var gotEpipe = false ;
67
85
var conn = net . connect ( { port : common . PORT } ) ;
68
86
69
87
var req = 'GET / HTTP/1.1\r\nHost: localhost:' +
@@ -72,17 +90,14 @@ function child() {
72
90
req = new Array ( 10241 ) . join ( req ) ;
73
91
74
92
conn . on ( 'connect' , function ( ) {
93
+ //kill child after 1s of flooding
94
+ setTimeout ( function ( ) { conn . destroy ( ) ; } , 1000 ) ;
75
95
write ( ) ;
76
96
} ) ;
77
97
78
98
conn . on ( 'drain' , write ) ;
79
99
80
- conn . on ( 'error' , function ( er ) {
81
- gotEpipe = true ;
82
- } ) ;
83
-
84
100
process . on ( 'exit' , function ( ) {
85
- assert ( gotEpipe ) ;
86
101
console . log ( 'ok - child' ) ;
87
102
} ) ;
88
103
0 commit comments