michael@0: var spdy = require('../spdy'), michael@0: http = require('http'), michael@0: res = http.ServerResponse.prototype; michael@0: michael@0: // michael@0: // ### function _renderHeaders () michael@0: // Copy pasted from lib/http.js michael@0: // (added lowercase) michael@0: // michael@0: exports._renderHeaders = function() { michael@0: if (this._header) { michael@0: throw new Error("Can't render headers after they are sent to the client."); michael@0: } michael@0: michael@0: var keys = Object.keys(this._headerNames); michael@0: for (var i = 0, l = keys.length; i < l; i++) { michael@0: var key = keys[i]; michael@0: this._headerNames[key] = this._headerNames[key].toLowerCase(); michael@0: } michael@0: michael@0: return res._renderHeaders.call(this); michael@0: }; michael@0: michael@0: // michael@0: // ### function writeHead (statusCode) michael@0: // #### @statusCode {Number} HTTP Status code michael@0: // .writeHead() wrapper michael@0: // (Sorry, copy pasted from lib/http.js) michael@0: // michael@0: exports.writeHead = function(statusCode) { michael@0: if (this._headerSent) return; michael@0: this._headerSent = true; michael@0: michael@0: var reasonPhrase, headers, headerIndex; michael@0: michael@0: if (typeof arguments[1] == 'string') { michael@0: reasonPhrase = arguments[1]; michael@0: headerIndex = 2; michael@0: } else { michael@0: reasonPhrase = http.STATUS_CODES[statusCode] || 'unknown'; michael@0: headerIndex = 1; michael@0: } michael@0: this.statusCode = statusCode; michael@0: michael@0: var obj = arguments[headerIndex]; michael@0: michael@0: if (obj && this._headers) { michael@0: // Slow-case: when progressive API and header fields are passed. michael@0: headers = this._renderHeaders(); michael@0: michael@0: // handle object case michael@0: var keys = Object.keys(obj); michael@0: for (var i = 0; i < keys.length; i++) { michael@0: var k = keys[i]; michael@0: if (k) headers[k] = obj[k]; michael@0: } michael@0: } else if (this._headers) { michael@0: // only progressive api is used michael@0: headers = this._renderHeaders(); michael@0: } else { michael@0: // only writeHead() called michael@0: headers = obj; michael@0: } michael@0: michael@0: // cleanup michael@0: this._header = ''; michael@0: michael@0: // Do not send data to new connections after GOAWAY michael@0: if (this.socket._isGoaway()) return; michael@0: michael@0: this.socket._lock(function() { michael@0: var socket = this; michael@0: michael@0: this._framer.replyFrame( michael@0: this.id, michael@0: statusCode, michael@0: reasonPhrase, michael@0: headers, michael@0: function (err, frame) { michael@0: // TODO: Handle err michael@0: socket.connection.write(frame); michael@0: socket._unlock(); michael@0: } michael@0: ); michael@0: }); michael@0: }; michael@0: michael@0: // michael@0: // ### function push (url, headers, callback) michael@0: // #### @url {String} absolute or relative url (from root anyway) michael@0: // #### @headers {Object} response headers michael@0: // #### @callbacks {Function} continuation that will receive stream object michael@0: // Initiates push stream michael@0: // michael@0: exports.push = function push(url, headers, priority, callback) { michael@0: if (this.socket._destroyed) { michael@0: return callback(Error('Can\'t open push stream, parent socket destroyed')); michael@0: } michael@0: michael@0: if (!callback && typeof priority === 'function') { michael@0: callback = priority; michael@0: priority = 0; michael@0: } michael@0: michael@0: if (!callback) callback = function() {}; michael@0: michael@0: this.socket._lock(function() { michael@0: var socket = this, michael@0: id = socket.connection.pushId += 2, michael@0: scheme = this._frame.headers.scheme, michael@0: host = this._frame.headers.host || 'localhost', michael@0: fullUrl = /^\//.test(url) ? scheme + '://' + host + url : url; michael@0: michael@0: this._framer.streamFrame( michael@0: id, michael@0: this.id, michael@0: { michael@0: method: 'GET', michael@0: path: url, michael@0: url: fullUrl, michael@0: scheme: scheme, michael@0: host: host, michael@0: version: 'HTTP/1.1', michael@0: priority: priority || 0 michael@0: }, michael@0: headers, michael@0: function(err, frame) { michael@0: if (err) { michael@0: socket._unlock(); michael@0: callback(err); michael@0: } else { michael@0: socket.connection.write(frame); michael@0: socket._unlock(); michael@0: michael@0: var stream = new spdy.server.Stream(socket.connection, { michael@0: type: 'SYN_STREAM', michael@0: push: true, michael@0: id: id, michael@0: assoc: socket.id, michael@0: priority: 0, michael@0: headers: {} michael@0: }); michael@0: michael@0: socket.connection.streams[id] = stream; michael@0: socket.pushes.push(stream); michael@0: michael@0: callback(null, stream); michael@0: } michael@0: } michael@0: ); michael@0: }); michael@0: };