|
1 var spdy = require('../spdy'), |
|
2 http = require('http'), |
|
3 res = http.ServerResponse.prototype; |
|
4 |
|
5 // |
|
6 // ### function _renderHeaders () |
|
7 // Copy pasted from lib/http.js |
|
8 // (added lowercase) |
|
9 // |
|
10 exports._renderHeaders = function() { |
|
11 if (this._header) { |
|
12 throw new Error("Can't render headers after they are sent to the client."); |
|
13 } |
|
14 |
|
15 var keys = Object.keys(this._headerNames); |
|
16 for (var i = 0, l = keys.length; i < l; i++) { |
|
17 var key = keys[i]; |
|
18 this._headerNames[key] = this._headerNames[key].toLowerCase(); |
|
19 } |
|
20 |
|
21 return res._renderHeaders.call(this); |
|
22 }; |
|
23 |
|
24 // |
|
25 // ### function writeHead (statusCode) |
|
26 // #### @statusCode {Number} HTTP Status code |
|
27 // .writeHead() wrapper |
|
28 // (Sorry, copy pasted from lib/http.js) |
|
29 // |
|
30 exports.writeHead = function(statusCode) { |
|
31 if (this._headerSent) return; |
|
32 this._headerSent = true; |
|
33 |
|
34 var reasonPhrase, headers, headerIndex; |
|
35 |
|
36 if (typeof arguments[1] == 'string') { |
|
37 reasonPhrase = arguments[1]; |
|
38 headerIndex = 2; |
|
39 } else { |
|
40 reasonPhrase = http.STATUS_CODES[statusCode] || 'unknown'; |
|
41 headerIndex = 1; |
|
42 } |
|
43 this.statusCode = statusCode; |
|
44 |
|
45 var obj = arguments[headerIndex]; |
|
46 |
|
47 if (obj && this._headers) { |
|
48 // Slow-case: when progressive API and header fields are passed. |
|
49 headers = this._renderHeaders(); |
|
50 |
|
51 // handle object case |
|
52 var keys = Object.keys(obj); |
|
53 for (var i = 0; i < keys.length; i++) { |
|
54 var k = keys[i]; |
|
55 if (k) headers[k] = obj[k]; |
|
56 } |
|
57 } else if (this._headers) { |
|
58 // only progressive api is used |
|
59 headers = this._renderHeaders(); |
|
60 } else { |
|
61 // only writeHead() called |
|
62 headers = obj; |
|
63 } |
|
64 |
|
65 // cleanup |
|
66 this._header = ''; |
|
67 |
|
68 // Do not send data to new connections after GOAWAY |
|
69 if (this.socket._isGoaway()) return; |
|
70 |
|
71 this.socket._lock(function() { |
|
72 var socket = this; |
|
73 |
|
74 this._framer.replyFrame( |
|
75 this.id, |
|
76 statusCode, |
|
77 reasonPhrase, |
|
78 headers, |
|
79 function (err, frame) { |
|
80 // TODO: Handle err |
|
81 socket.connection.write(frame); |
|
82 socket._unlock(); |
|
83 } |
|
84 ); |
|
85 }); |
|
86 }; |
|
87 |
|
88 // |
|
89 // ### function push (url, headers, callback) |
|
90 // #### @url {String} absolute or relative url (from root anyway) |
|
91 // #### @headers {Object} response headers |
|
92 // #### @callbacks {Function} continuation that will receive stream object |
|
93 // Initiates push stream |
|
94 // |
|
95 exports.push = function push(url, headers, priority, callback) { |
|
96 if (this.socket._destroyed) { |
|
97 return callback(Error('Can\'t open push stream, parent socket destroyed')); |
|
98 } |
|
99 |
|
100 if (!callback && typeof priority === 'function') { |
|
101 callback = priority; |
|
102 priority = 0; |
|
103 } |
|
104 |
|
105 if (!callback) callback = function() {}; |
|
106 |
|
107 this.socket._lock(function() { |
|
108 var socket = this, |
|
109 id = socket.connection.pushId += 2, |
|
110 scheme = this._frame.headers.scheme, |
|
111 host = this._frame.headers.host || 'localhost', |
|
112 fullUrl = /^\//.test(url) ? scheme + '://' + host + url : url; |
|
113 |
|
114 this._framer.streamFrame( |
|
115 id, |
|
116 this.id, |
|
117 { |
|
118 method: 'GET', |
|
119 path: url, |
|
120 url: fullUrl, |
|
121 scheme: scheme, |
|
122 host: host, |
|
123 version: 'HTTP/1.1', |
|
124 priority: priority || 0 |
|
125 }, |
|
126 headers, |
|
127 function(err, frame) { |
|
128 if (err) { |
|
129 socket._unlock(); |
|
130 callback(err); |
|
131 } else { |
|
132 socket.connection.write(frame); |
|
133 socket._unlock(); |
|
134 |
|
135 var stream = new spdy.server.Stream(socket.connection, { |
|
136 type: 'SYN_STREAM', |
|
137 push: true, |
|
138 id: id, |
|
139 assoc: socket.id, |
|
140 priority: 0, |
|
141 headers: {} |
|
142 }); |
|
143 |
|
144 socket.connection.streams[id] = stream; |
|
145 socket.pushes.push(stream); |
|
146 |
|
147 callback(null, stream); |
|
148 } |
|
149 } |
|
150 ); |
|
151 }); |
|
152 }; |