"use strict";var crypto=require("crypto"),url=require("url"),util=require("util"),HttpParser=require("../http_parser"),Base=require("./base"),Hybi=require("./hybi"),Proxy=require("./proxy"),Client=function(e,t){this.version="hybi-13",Hybi.call(this,null,e,t),this.readyState=-1,this._key=Client.generateKey(),this._accept=Hybi.generateAccept(this._key),this._http=new HttpParser("response");var s=url.parse(this.url),i=s.auth&&new Buffer(s.auth,"utf8").toString("base64");if(this.VALID_PROTOCOLS.indexOf(s.protocol)<0)throw new Error(this.url+" is not a valid WebSocket URL");this._pathname=(s.pathname||"/")+(s.search||""),this._headers.set("Host",s.host),this._headers.set("Upgrade","websocket"),this._headers.set("Connection","Upgrade"),this._headers.set("Sec-WebSocket-Key",this._key),this._headers.set("Sec-WebSocket-Version","13"),this._protocols.length>0&&this._headers.set("Sec-WebSocket-Protocol",this._protocols.join(", ")),i&&this._headers.set("Authorization","Basic "+i)};util.inherits(Client,Hybi),Client.generateKey=function(){return crypto.randomBytes(16).toString("base64")};var instance={VALID_PROTOCOLS:["ws:","wss:"],proxy:function(e,t){return new Proxy(this,e,t)},start:function(){return-1===this.readyState&&(this._write(this._handshakeRequest()),this.readyState=0,!0)},parse:function(e){if(3!==this.readyState){if(this.readyState>0)return Hybi.prototype.parse.call(this,e);this._http.parse(e),this._http.isComplete()&&(this._validateHandshake(),3!==this.readyState&&(this._open(),this.parse(this._http.body)))}},_handshakeRequest:function(){var e=this._extensions.generateOffer();e&&this._headers.set("Sec-WebSocket-Extensions",e);var t=["GET "+this._pathname+" HTTP/1.1",this._headers.toString(),""];return new Buffer(t.join("\r\n"),"utf8")},_failHandshake:function(e){e="Error during WebSocket handshake: "+e,this.readyState=3,this.emit("error",new Error(e)),this.emit("close",new Base.CloseEvent(this.ERRORS.protocol_error,e))},_validateHandshake:function(){if(this.statusCode=this._http.statusCode,this.headers=this._http.headers,this._http.error)return this._failHandshake(this._http.error.message);if(101!==this._http.statusCode)return this._failHandshake("Unexpected response code: "+this._http.statusCode);var e=this._http.headers,t=e.upgrade||"",s=e.connection||"",i=e["sec-websocket-accept"]||"",r=e["sec-websocket-protocol"]||"";if(""===t)return this._failHandshake("'Upgrade' header is missing");if("websocket"!==t.toLowerCase())return this._failHandshake("'Upgrade' header value is not 'WebSocket'");if(""===s)return this._failHandshake("'Connection' header is missing");if("upgrade"!==s.toLowerCase())return this._failHandshake("'Connection' header value is not 'Upgrade'");if(i!==this._accept)return this._failHandshake("Sec-WebSocket-Accept mismatch");if(this.protocol=null,""!==r){if(this._protocols.indexOf(r)<0)return this._failHandshake("Sec-WebSocket-Protocol mismatch");this.protocol=r}try{this._extensions.activate(this.headers["sec-websocket-extensions"])}catch(e){return this._failHandshake(e.message)}}};for(var key in instance)Client.prototype[key]=instance[key];module.exports=Client;