func(u *Upgrader)Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header)(*Conn,error){const badHandshake ="websocket: the client is not using the websocket protocol: "//1.校验是否携带了表示升级为webSocket的请求头if!tokenListContainsValue(r.Header,"Connection","upgrade"){return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header")}if!tokenListContainsValue(r.Header,"Upgrade","websocket"){return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header")}//2.校验是否是get请求if r.Method != http.MethodGet {return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")}//3.校验是否携带了Websocket版本号等信息if!tokenListContainsValue(r.Header,"Sec-Websocket-Version","13"){return u.returnError(w, r, http.StatusBadRequest,"websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")}if_, ok := responseHeader["Sec-Websocket-Extensions"]; ok {return u.returnError(w, r, http.StatusInternalServerError,"websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported")}
checkOrigin := u.CheckOrigin
if checkOrigin ==nil{
checkOrigin = checkSameOrigin
}if!checkOrigin(r){return u.returnError(w, r, http.StatusForbidden,"websocket: request origin not allowed by Upgrader.CheckOrigin")}//4.获取Sec-Websocket-Key
challengeKey := r.Header.Get("Sec-Websocket-Key")if challengeKey ==""{return u.returnError(w, r, http.StatusBadRequest,"websocket: not a websocket handshake: 'Sec-WebSocket-Key' header is missing or blank")}
subprotocol := u.selectSubprotocol(r, responseHeader)// Negotiate PMCEvar compress boolif u.EnableCompression {for_, ext :=rangeparseExtensions(r.Header){if ext[""]!="permessage-deflate"{continue}
compress =truebreak}}
h, ok := w.(http.Hijacker)if!ok {return u.returnError(w, r, http.StatusInternalServerError,"websocket: response does not implement http.Hijacker")}var brw *bufio.ReadWriter
//5.获取连接
netConn, brw, err := h.Hijack()if err !=nil{return u.returnError(w, r, http.StatusInternalServerError, err.Error())}if brw.Reader.Buffered()>0{
netConn.Close()returnnil, errors.New("websocket: client sent data before handshake is complete")}var br *bufio.Reader
if u.ReadBufferSize ==0&&bufioReaderSize(netConn, brw.Reader)>256{// Reuse hijacked buffered reader as connection reader.
br = brw.Reader
}
buf :=bufioWriterBuffer(netConn, brw.Writer)var writeBuf []byteif u.WriteBufferPool ==nil&& u.WriteBufferSize ==0&&len(buf)>= maxFrameHeaderSize+256{// Reuse hijacked write buffer as connection buffer.
writeBuf = buf
}//6.对拿到的连接进行封装,封装为实现了读数据和写数据方法的Conn结构
c :=newConn(netConn,true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf)
c.subprotocol = subprotocol
if compress {
c.newCompressionWriter = compressNoContextTakeover
c.newDecompressionReader = decompressNoContextTakeover
}// Use larger of hijacked buffer and connection write buffer for header.
p := buf
iflen(c.writeBuf)>len(p){
p = c.writeBuf
}
p = p[:0]//7.构建webSocket响应标识,例如101状态码等等
p =append(p,"HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
p =append(p,computeAcceptKey(challengeKey)...)
p =append(p,"\r\n"...)if c.subprotocol !=""{
p =append(p,"Sec-WebSocket-Protocol: "...)
p =append(p, c.subprotocol...)
p =append(p,"\r\n"...)}if compress {
p =append(p,"Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)}for k, vs :=range responseHeader {if k =="Sec-Websocket-Protocol"{continue}for_, v :=range vs {
p =append(p, k...)
p =append(p,": "...)for i :=0; i <len(v); i++{
b := v[i]if b <=31{// prevent response splitting.
b =' '}
p =append(p, b)}
p =append(p,"\r\n"...)}}
p =append(p,"\r\n"...)// Clear deadlines set by HTTP server.
netConn.SetDeadline(time.Time{})if u.HandshakeTimeout >0{
netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))}//8.将webSocket标识响应写出if_, err = netConn.Write(p); err !=nil{
netConn.Close()returnnil, err
}if u.HandshakeTimeout >0{
netConn.SetWriteDeadline(time.Time{})}//9.返回封装的Connreturn c,nil}