func Unpack(reader *bufio.Reader) ([]byte, error) { return reader.ReadBytes('\n') //if global.PackSplitType =="breakline" { // return reader.ReadBytes('\n') //} lengthByte, _ := reader.Peek(4) lengthBuff := bytes.NewBuffer(lengthByte) var length int32 err := binary.Read(lengthBuff, binary.LittleEndian, &length) if err != nil { return nil, err } fmt.Println("Get length :", length) if int32(reader.Buffered()) < length+4 { return nil, err } pack := make([]byte, int(4+length)) _, err = reader.Read(pack) if err != nil { return nil, err } return pack[4:], nil }
func (self ProtobufProbe) DeserializeByReader(reader *bufio.Reader) (*protocol.MobileSuiteModel, int32, error) { lengthByte, _ := reader.Peek(4) lengthBuff := bytes.NewBuffer(lengthByte) var length int32 err := binary.Read(lengthBuff, binary.LittleEndian, &length) if err != nil { log.Error("when deserializeByReader:", err.Error()) return nil, -1, err } if int32(reader.Buffered()) < length+4 { log.Error("int32(reader.Buffered()) < length + 4") return nil, -1, err } pack := make([]byte, int(4+length)) _, err = reader.Read(pack) if err != nil { log.Error("when deserializeByReader:", err.Error()) return nil, -1, err } var dst protocol.MobileSuiteModel var msgType int32 msgType, err = self.Deserialize(pack, &dst) log.Debug(length, msgType, dst) return &dst, msgType, nil }
func handshake(client net.Conn, config *Config) (bouncer *BouncerConfig, remainder []byte) { // Setup a buffered reader over the client. var reader *bufio.Reader = bufio.NewReader(client) // Attempt to handshake with the client and determine the requested config. var match chan *BouncerConfig = make(chan *BouncerConfig, 1) go seekshake(reader, config, match) // Block until handshake is done or we hit our timeout. select { case bouncer = <-match: // Grab the remaining portion of the handshake. remainder = make([]byte, reader.Buffered()) reader.Read(remainder) if bouncer != nil { log.Printf("LOGIN %s", client.RemoteAddr()) } else { log.Printf("REJECT %s", client.RemoteAddr()) } return bouncer, remainder case <-time.After(time.Duration(config.Auth.Timeout) * time.Second): log.Printf("TIMEOUT %s", client.RemoteAddr()) return nil, []byte{} } }
func deserializeByReader(reader *bufio.Reader) (*pb.MobileSuiteProtobuf, error) { buff, _ := reader.Peek(4) data := bytes.NewBuffer(buff) var length int32 err := binary.Read(data, binary.BigEndian, &length) if err != nil { return nil, err } fmt.Println(length) if int32(reader.Buffered()) < length+4 { return nil, err } pack := make([]byte, int(4+length)) _, err = reader.Read(pack) if err != nil { return nil, err } msg := pack[4:] var dst pb.MobileSuiteProtobuf proto.Unmarshal(msg, &dst) fmt.Println(&dst) var testMsg pb.TestMessage proto.Unmarshal(dst.Message, &testMsg) fmt.Println(&testMsg) return &dst, nil }
func mustPeekBuffered(r *bufio.Reader) []byte { buf, err := r.Peek(r.Buffered()) if len(buf) == 0 || err != nil { panic(fmt.Sprintf("bufio.Reader.Peek() returned unexpected data (%q, %v)", buf, err)) } return buf }
func HijackRequest(req *http.Request, dial func(string, string) (net.Conn, error)) (*http.Response, ReadWriteCloser, error) { if dial == nil { dial = net.Dial } conn, err := dial("tcp", req.URL.Host) if err != nil { return nil, nil, err } clientconn := httputil.NewClientConn(conn, nil) res, err := clientconn.Do(req) if err != nil && err != httputil.ErrPersistEOF { return nil, nil, err } if res.StatusCode != http.StatusSwitchingProtocols { return res, nil, &url.Error{ Op: req.Method, URL: req.URL.String(), Err: fmt.Errorf("controller: unexpected status %d", res.StatusCode), } } var rwc io.ReadWriteCloser var buf *bufio.Reader rwc, buf = clientconn.Hijack() if buf.Buffered() > 0 { rwc = struct { io.Reader writeCloser }{ io.MultiReader(io.LimitReader(buf, int64(buf.Buffered())), rwc), rwc.(writeCloser), } } return res, rwc.(ReadWriteCloser), nil }
func fullRuneBuffered(br *bufio.Reader) bool { n := br.Buffered() buf, err := br.Peek(n) if err != nil { return false } return utf8.FullRune(buf) }
func bufferFullError(r *bufio.Reader) error { n := r.Buffered() b, err := r.Peek(n) if err != nil { panic(fmt.Sprintf("BUG: unexpected error returned from bufio.Reader.Peek(Buffered()): %s", err)) } bStart, bEnd := bufferStartEnd(b) return fmt.Errorf("headers exceed %d bytes. Increase ReadBufferSize. buf=%q...%q", n, bStart, bEnd) }
// Learned from net.textproto. One difference is that this one keeps the // ending '\n' in the returned line. Buf if there's only CRLF in the line, // return nil for the line. func readContinuedLineSlice(r *bufio.Reader) ([]byte, error) { // feedly.com request headers contains things like: // "$Authorization.feedly: $FeedlyAuth\r\n", so we must test for only // continuation spaces. isspace := func(b byte) bool { return b == ' ' || b == '\t' } // Read the first line. line, err := r.ReadSlice('\n') if err != nil && err != io.EOF { return nil, err } // There are servers that use \n for line ending, so trim first before check ending. // For example, the 404 page for http://plan9.bell-labs.com/magic/man2html/1/2l trimmed := TrimSpace(line) if len(trimmed) == 0 { if len(line) > 2 { return nil, fmt.Errorf("malformed end of headers, len: %d, %#v", len(line), string(line)) } return nil, nil } if isspace(line[0]) { return nil, fmt.Errorf("malformed header, start with space: %#v", string(line)) } // Optimistically assume that we have started to buffer the next line // and it starts with an ASCII letter (the next header key), so we can // avoid copying that buffered data around in memory and skipping over // non-existent whitespace. if r.Buffered() > 0 { peek, err := r.Peek(1) if err == nil && !isspace(peek[0]) { return line, nil } } var buf []byte buf = append(buf, trimmed...) // Read continuation lines. for skipSpace(r) > 0 { line, err := r.ReadSlice('\n') if err != nil { break } buf = append(buf, ' ') buf = append(buf, TrimTrailingSpace(line)...) } buf = append(buf, '\r', '\n') return buf, nil }
// convert from net/textproto/reader.go:Reader.upcomingHeaderNewlines func peekRequestLine(r *bufio.Reader) ([]byte, error) { r.Peek(1) // force a buffer load if empty s := r.Buffered() if s == 0 { return nil, errors.New("No request in connection") } peek, _ := r.Peek(s) line, err := bytes.NewBuffer(peek).ReadBytes('\n') if err != nil { return nil, errors.New("Bad request in connection") } return line, nil }
func (c *Client) Hijack(method, path string, header http.Header, in interface{}) (ReadWriteCloser, error) { uri, err := url.Parse(c.URL) if err != nil { return nil, err } dial := c.HijackDial if dial == nil { dial = net.Dial } conn, err := dial("tcp", uri.Host) if err != nil { return nil, err } clientconn := httputil.NewClientConn(conn, nil) req, err := c.prepareReq(method, path, header, in) if err != nil { return nil, err } req.Header.Set("Connection", "upgrade") res, err := clientconn.Do(req) if err != nil && err != httputil.ErrPersistEOF { return nil, err } if res.StatusCode != http.StatusSwitchingProtocols { defer res.Body.Close() if strings.Contains(res.Header.Get("Content-Type"), "application/json") { var jsonErr httphelper.JSONError if err := json.NewDecoder(res.Body).Decode(&jsonErr); err == nil { return nil, jsonErr } } return nil, &url.Error{ Op: req.Method, URL: req.URL.String(), Err: fmt.Errorf("httpclient: unexpected status %d", res.StatusCode), } } var rwc io.ReadWriteCloser var buf *bufio.Reader rwc, buf = clientconn.Hijack() if buf.Buffered() > 0 { rwc = struct { io.Reader writeCloser }{ io.MultiReader(io.LimitReader(buf, int64(buf.Buffered())), rwc), rwc.(writeCloser), } } return rwc.(ReadWriteCloser), nil }
// Flush any data buffered in a bufio.Reader to a designated io.Writer. // Used for transitioning from SOCKS negotiation to data-forwarding mode. func bufFlush(br *bufio.Reader, w io.Writer) error { n := br.Buffered() if n == 0 { return nil // nothing buffered to flush } buf := make([]byte, n) if _, err := io.ReadFull(br, buf); err != nil { return err } _, err := w.Write(buf) return err }
// Read reads response header from r. func (h *ResponseHeader) Read(r *bufio.Reader) error { n := 1 for { err := h.tryRead(r, n) if err == nil { return nil } if err != errNeedMore { h.Reset() return err } n = r.Buffered() + 1 } }
// Read reads request header from r. // // io.EOF is returned if r is closed before reading the first header byte. func (h *RequestHeader) Read(r *bufio.Reader) error { n := 1 for { err := h.tryRead(r, n) if err == nil { return nil } if err != errNeedMore { h.resetSkipNormalize() return err } n = r.Buffered() + 1 } }
func doLineRead(r *bufio.Reader) { line, prefix, err := r.ReadLine() if err != nil { log.Fatalf("failed reading a line: %s", err) } log.Printf("Got the rest of the line: %s", line) if prefix { log.Printf("Line too big for buffer, only first %d bytes returned", len(line)) } else { log.Printf("Line fit in buffer, full line returned") } log.Printf("After all that, %d bytes are buffered", r.Buffered()) }
func Decode(reader *bufio.Reader) (string, error) { lengthByte, _ := reader.Peek(4) lengthBuff := bytes.NewBuffer(lengthByte) var length int32 err := binary.Read(lengthBuff, binary.LittleEndian, &length) if err != nil { return "", err } if int32(reader.Buffered()) < length+4 { return "", err } pack := make([]byte, int(4+length)) _, err = reader.Read(pack) if err != nil { return "", err } return string(pack[4:]), nil }
func decodeContent(reader *bufio.Reader) (string, error) { // 获取读取的内容长度 var length int lenBytes, err := reader.Peek(4) err = binary.Read(bytes.NewBuffer(lenBytes), binary.LittleEndian, &length) if err != nil { return "", err } // 判断是否是完整的包 if reader.Buffered() < 4+length { return "", err } // 获取完整包的内容 var bytes []byte = make([]byte, 4+length) _, err = reader.Read(bytes) if err != nil { return "", err } return string(bytes[4:]), nil }
// tunneling to backend func tunneling(addr string, rdr *bufio.Reader, c net.Conn, header *bytes.Buffer) error { backend, err := dialTimeout("tcp", addr, time.Second*time.Duration(_BackendDialTimeout)) if err != nil { // handle error switch err := err.(type) { case net.Error: if err.Timeout() { writeErrCode(c, []byte("4101"), false) return err } } writeErrCode(c, []byte("4102"), false) return err } defer backend.Close() if header != nil { header.WriteTo(backend) } if n := rdr.Buffered(); n > 0 { var data []byte data, err = rdr.Peek(n) if err != nil { writeErrCode(c, []byte("4103"), false) return err } _, err = backend.Write(data) if err != nil { writeErrCode(c, []byte("4102"), false) return err } } rdr.Reset(nil) _BufioReaderPool.Put(rdr) // Start transfering data go pipe(c, backend) pipe(backend, c) return nil }
// parseCmdSize get the request protocol cmd size. func parseCmdSize(rd *bufio.Reader, prefix uint8) (int, error) { // get command size cs, err := rd.ReadBytes('\n') if err != nil { log.Debug("received:%d %s", rd.Buffered(), rd) log.Error("tcp:rd.ReadBytes('\\n') error(%v)", err) return 0, err } csl := len(cs) if csl <= 3 || cs[0] != prefix || cs[csl-2] != '\r' { log.Error("tcp:\"%v\"(%d) number format error, length error or prefix error or no \\r", cs, csl) return 0, ErrProtocol } // skip the \r\n cmdSize, err := strconv.Atoi(string(cs[1 : csl-2])) if err != nil { log.Error("tcp:\"%v\" number parse int error(%v)", cs, err) return 0, ErrProtocol } return cmdSize, nil }
//当error为ErrUnexpectedRESPEOF时,说明还缺少数据,并不是一个完整的bulk string //还缺少的数据由第二个参数返回,其余n的值则都是0 func parseBulkString(line []byte, br *bufio.Reader) (RESP_BULK_STRING, int, error) { neededDataLen := 0 n, err := parseLen(line[0:]) if n < 0 || err != nil { return "", neededDataLen, err } brSize := br.Buffered() //n+2: bulkString + "\r\n" if n+2 > brSize { neededDataLen = n + 2 - brSize return "", neededDataLen, ErrUnexpectedRESPEOF } p, _ := br.Peek(n) br.Discard(n) if line, err := readLine(br); err != nil { return "", neededDataLen, err } else if len(line) != 0 { return "", neededDataLen, errors.New("bad bulk string format") } return RESP_BULK_STRING(p), neededDataLen, nil }
func recvFrame(rd *bufio.Reader, m proto.Message) (err error) { var ( d []byte vsize int64 size int ) if vsize, err = binary.ReadVarint(rd); err != nil || vsize == 0 { return } else { size = int(vsize) } if rd.Buffered() >= size { // Parse proto directly from the buffered data. if d, err = rd.Peek(size); err != nil { return } // simply discard if m != nil { if err = proto.Unmarshal(d, m); err != nil { return } } // TODO(pmattis): This is a hack to advance the bufio pointer by // reading into the same slice that bufio.Reader.Peek // returned. In Go 1.5 we'll be able to use // bufio.Reader.Discard. _, err = io.ReadFull(rd, d) return } d = make([]byte, size) if _, err = io.ReadFull(rd, d); err != nil { return } // simply discard if m != nil { return proto.Unmarshal(d, m) } return }
func readAndUnpack(reader *bufio.Reader) (header []byte, servers []Server, more bool, error error) { header, error = reader.ReadBytes(0x0A) if error != nil { return } more = true servers = make([]Server, 0) serverBuffer := make([]byte, 6) for reader.Buffered() >= 6 { if _, readError := reader.Read(serverBuffer); readError != nil { return nil, nil, false, readError } if server := unpackSingleServer(serverBuffer); !server.isNullServer() { servers = append(servers, server) } else { more = false break } } return }
func sendBodySplitIntoChunk(w io.Writer, r *bufio.Reader) (err error) { // debug.Printf("sendBodySplitIntoChunk called\n") var b []byte for { b = make([]byte, r.Buffered()) _, err = r.Read(b) // debug.Println("split into chunk n =", n, "err =", err) if err != nil { if err == io.EOF { // EOF is expected here as the server is closing connection. // debug.Println("end chunked encoding") _, err = w.Write([]byte(chunkEnd)) if err != nil { debug.Println("write chunk end 0", err) } return } debug.Println("read error in sendBodySplitIntoChunk", err) return } chunkSize := []byte(fmt.Sprintf("%x\r\n", len(b))) if _, err = w.Write(chunkSize); err != nil { debug.Printf("write chunk size %v\n", err) return } if _, err = w.Write(b); err != nil { debug.Println("write chunk data:", err) return } if _, err = w.Write([]byte(CRLF)); err != nil { debug.Println("write chunk ending CRLF:", err) return } } }
func parseReader(reader *bufio.Reader) (ls []*Link) { for { c, err := reader.Peek(len(" ")) if err != nil { return } if string(c) != " " { break } reader.ReadRune() } if r, _, _ := reader.ReadRune(); strconv.QuoteRune(r) != "'<'" { log.Println("Bad format, there should be a < to start the link, got", strconv.QuoteRune(r)) var errBuff bytes.Buffer io.Copy(&errBuff, reader) log.Println(errBuff.String()) return } // Read url, between < and > var urlBuff bytes.Buffer for { r, _, err := reader.ReadRune() if err != nil { return } if strconv.QuoteRune(r) == "'>'" { break } urlBuff.WriteRune(r) } // trim following spaces until ; for { r, _, _ := reader.ReadRune() if strconv.QuoteRune(r) == "';'" { break } } // Here, we already read ; rel := "" for { key, value, endOfParams, err := nextParams(reader) if err != nil { if err != io.EOF { log.Println("Error when parsing params:", err.Error()) return } break } if key == "rel" { rel = value } if endOfParams { break } } thisLink := &Link{ Uri: urlBuff.String(), Rel: rel, } allLinks := []*Link{thisLink} if reader.Buffered() > 0 { for _, l := range parseReader(reader) { allLinks = append(allLinks, l) } } return allLinks }
func (s *Server) serveConn(c net.Conn) error { currentTime := time.Now() connTime := currentTime connRequestNum := uint64(0) ctx := s.acquireCtx(c) var br *bufio.Reader var bw *bufio.Writer var err error var connectionClose bool var isHTTP11 bool var timeoutResponse *Response var hijackHandler HijackHandler for { ctx.id++ connRequestNum++ ctx.time = currentTime if s.ReadTimeout > 0 || s.MaxKeepaliveDuration > 0 { readTimeout := s.ReadTimeout if s.MaxKeepaliveDuration > 0 { connTimeout := s.MaxKeepaliveDuration - currentTime.Sub(connTime) if connTimeout <= 0 { err = ErrKeepaliveTimeout break } if connTimeout < readTimeout { readTimeout = connTimeout } } if err = c.SetReadDeadline(currentTime.Add(readTimeout)); err != nil { panic(fmt.Sprintf("BUG: error in SetReadDeadline(%s): %s", readTimeout, err)) } } if !(s.ReduceMemoryUsage || ctx.lastReadDuration > time.Second) || br != nil { if br == nil { br = acquireReader(ctx) } } else { br, err = acquireByteReader(&ctx) } if err == nil { err = ctx.Request.readLimitBody(br, s.MaxRequestBodySize, s.GetOnly) if br.Buffered() == 0 || err != nil { releaseReader(s, br) br = nil } } currentTime = time.Now() ctx.lastReadDuration = currentTime.Sub(ctx.time) if err != nil { if err == io.EOF { err = nil } break } // 'Expect: 100-continue' request handling. // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html for details. if !ctx.Request.Header.noBody() && ctx.Request.MayContinue() { // Send 'HTTP/1.1 100 Continue' response. if bw == nil { bw = acquireWriter(ctx) } bw.Write(strResponseContinue) err = bw.Flush() releaseWriter(s, bw) bw = nil if err != nil { break } // Read request body. if br == nil { br = acquireReader(ctx) } err = ctx.Request.ContinueReadBody(br, s.MaxRequestBodySize) if br.Buffered() == 0 || err != nil { releaseReader(s, br) br = nil } if err != nil { break } } ctx.connRequestNum = connRequestNum ctx.connTime = connTime ctx.time = currentTime s.Handler(ctx) connectionClose = ctx.Request.Header.connectionCloseFast() isHTTP11 = ctx.Request.Header.IsHTTP11() if !ctx.IsGet() && ctx.IsHead() { ctx.Response.SkipBody = true } ctx.Request.Reset() hijackHandler = ctx.hijackHandler ctx.hijackHandler = nil ctx.userValues.Reset() timeoutResponse = ctx.timeoutResponse if timeoutResponse != nil { ctx = s.acquireCtx(c) timeoutResponse.CopyTo(&ctx.Response) if br != nil { // Close connection, since br may be attached to the old ctx via ctx.fbr. ctx.SetConnectionClose() } } if s.MaxRequestsPerConn > 0 && connRequestNum >= uint64(s.MaxRequestsPerConn) { ctx.SetConnectionClose() } if s.WriteTimeout > 0 || s.MaxKeepaliveDuration > 0 { writeTimeout := s.WriteTimeout if s.MaxKeepaliveDuration > 0 { connTimeout := s.MaxKeepaliveDuration - time.Since(connTime) if connTimeout <= 0 { // MaxKeepAliveDuration exceeded, but let's try sending response anyway // in 100ms with 'Connection: close' header. ctx.SetConnectionClose() connTimeout = 100 * time.Millisecond } if connTimeout < writeTimeout { writeTimeout = connTimeout } } if err = c.SetWriteDeadline(time.Now().Add(writeTimeout)); err != nil { panic(fmt.Sprintf("BUG: error in SetWriteDeadline(%s): %s", writeTimeout, err)) } } connectionClose = connectionClose || ctx.Response.ConnectionClose() if connectionClose { ctx.Response.Header.SetCanonical(strConnection, strClose) } else if !isHTTP11 { // Set 'Connection: keep-alive' response header for non-HTTP/1.1 request. // There is no need in setting this header for http/1.1, since in http/1.1 // connections are keep-alive by default. ctx.Response.Header.SetCanonical(strConnection, strKeepAlive) } if bw == nil { bw = acquireWriter(ctx) } if err = writeResponse(ctx, bw); err != nil { break } if br == nil || connectionClose { err = bw.Flush() releaseWriter(s, bw) bw = nil if err != nil { break } if connectionClose { break } } if hijackHandler != nil { var hjr io.Reader hjr = c if br != nil { hjr = br br = nil // br may point to ctx.fbr, so do not return ctx into pool. ctx = s.acquireCtx(c) } if bw != nil { err = bw.Flush() releaseWriter(s, bw) bw = nil if err != nil { break } } c.SetReadDeadline(zeroTime) c.SetWriteDeadline(zeroTime) go hijackConnHandler(hjr, c, s, hijackHandler) hijackHandler = nil err = errHijacked break } currentTime = time.Now() } if br != nil { releaseReader(s, br) } if bw != nil { releaseWriter(s, bw) } s.releaseCtx(ctx) return err }
// Upgrade upgrades the HTTP server connection to the WebSocket protocol. // // The responseHeader is included in the response to the client's upgrade // request. Use the responseHeader to specify cookies (Set-Cookie) and the // application negotiated subprotocol (Sec-Websocket-Protocol). // // If the upgrade fails, then Upgrade replies to the client with an HTTP error // response. func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { if r.Method != "GET" { return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method not GET") } if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok { return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific Sec-Websocket-Extensions headers are unsupported") } if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") { return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13") } if !tokenListContainsValue(r.Header, "Connection", "upgrade") { return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'") } if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'") } checkOrigin := u.CheckOrigin if checkOrigin == nil { checkOrigin = checkSameOrigin } if !checkOrigin(r) { return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed") } challengeKey := r.Header.Get("Sec-Websocket-Key") if challengeKey == "" { return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank") } subprotocol := u.selectSubprotocol(r, responseHeader) // Negotiate PMCE var compress bool if u.EnableCompression { for _, ext := range parseExtensions(r.Header) { if ext[""] != "permessage-deflate" { continue } compress = true break } } var ( netConn net.Conn br *bufio.Reader err error ) h, ok := w.(http.Hijacker) if !ok { return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") } var rw *bufio.ReadWriter netConn, rw, err = h.Hijack() if err != nil { return u.returnError(w, r, http.StatusInternalServerError, err.Error()) } br = rw.Reader if br.Buffered() > 0 { netConn.Close() return nil, errors.New("websocket: client sent data before handshake is complete") } c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize) c.subprotocol = subprotocol if compress { c.newCompressionWriter = compressNoContextTakeover c.newDecompressionReader = decompressNoContextTakeover } p := c.writeBuf[:0] 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)) } if _, err = netConn.Write(p); err != nil { netConn.Close() return nil, err } if u.HandshakeTimeout > 0 { netConn.SetWriteDeadline(time.Time{}) } return c, nil }
// Upgrade upgrades the HTTP server connection to the WebSocket protocol. // // The responseHeader is included in the response to the client's upgrade // request. Use the responseHeader to specify cookies (Set-Cookie) and the // application negotiated subprotocol (Sec-Websocket-Protocol). func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" { return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13") } if !tokenListContainsValue(r.Header, "Connection", "upgrade") { return u.returnError(w, r, http.StatusBadRequest, "websocket: connection header != upgrade") } if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { return u.returnError(w, r, http.StatusBadRequest, "websocket: upgrade != websocket") } checkOrigin := u.CheckOrigin if checkOrigin == nil { checkOrigin = checkSameOrigin } if !checkOrigin(r) { return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed") } challengeKey := r.Header.Get("Sec-Websocket-Key") if challengeKey == "" { return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank") } subprotocol := u.selectSubprotocol(r, responseHeader) var ( netConn net.Conn br *bufio.Reader err error ) h, ok := w.(http.Hijacker) if !ok { return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") } var rw *bufio.ReadWriter netConn, rw, err = h.Hijack() br = rw.Reader if br.Buffered() > 0 { netConn.Close() return nil, errors.New("websocket: client sent data before handshake is complete") } readBufSize := u.ReadBufferSize if readBufSize == 0 { readBufSize = defaultReadBufferSize } writeBufSize := u.WriteBufferSize if writeBufSize == 0 { writeBufSize = defaultWriteBufferSize } c := newConn(netConn, true, readBufSize, writeBufSize) c.subprotocol = subprotocol p := c.writeBuf[:0] 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"...) } 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"...) if u.HandshakeTimeout > 0 { netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)) } if _, err = netConn.Write(p); err != nil { netConn.Close() return nil, err } return c, nil }
func (s *Server) serveConn(c net.Conn) error { currentTime := time.Now() connTime := currentTime connRequestNum := uint64(0) ctx := s.acquireCtx(c) var br *bufio.Reader var bw *bufio.Writer var err error var connectionClose bool var errMsg string for { ctx.id++ connRequestNum++ ctx.time = currentTime if s.ReadTimeout > 0 || s.MaxKeepaliveDuration > 0 { readTimeout := s.ReadTimeout if s.MaxKeepaliveDuration > 0 { connTimeout := s.MaxKeepaliveDuration - currentTime.Sub(connTime) if connTimeout <= 0 { err = ErrKeepaliveTimeout break } if connTimeout < readTimeout { readTimeout = connTimeout } } if err = c.SetReadDeadline(currentTime.Add(readTimeout)); err != nil { break } } if !(s.ReduceMemoryUsage || ctx.lastReadDuration > time.Second) || br != nil { if br == nil { br = acquireReader(ctx) } err = ctx.Request.Read(br) if br.Buffered() == 0 || err != nil { releaseReader(s, br) br = nil } } else { br, err = acquireByteReader(&ctx) if err == nil { err = ctx.Request.Read(br) if br.Buffered() == 0 || err != nil { releaseReader(s, br) br = nil } } } currentTime = time.Now() ctx.lastReadDuration = currentTime.Sub(ctx.time) if err != nil { if err == io.EOF { err = nil } break } ctx.connRequestNum = connRequestNum ctx.connTime = connTime ctx.time = currentTime ctx.Response.Reset() s.Handler(ctx) errMsg = ctx.timeoutErrMsg if len(errMsg) > 0 { ctx = s.acquireCtx(c) ctx.Error(errMsg, StatusRequestTimeout) if br != nil { // Close connection, since br may be attached to the old ctx via ctx.fbr. ctx.SetConnectionClose() } } if s.MaxRequestsPerConn > 0 && connRequestNum >= uint64(s.MaxRequestsPerConn) { ctx.SetConnectionClose() } if s.WriteTimeout > 0 || s.MaxKeepaliveDuration > 0 { writeTimeout := s.WriteTimeout if s.MaxKeepaliveDuration > 0 { connTimeout := s.MaxKeepaliveDuration - time.Since(connTime) if connTimeout <= 0 { // MaxKeepAliveDuration exceeded, but let's try sending response anyway // in 100ms with 'Connection: close' header. ctx.SetConnectionClose() connTimeout = 100 * time.Millisecond } if connTimeout < writeTimeout { writeTimeout = connTimeout } } if err = c.SetWriteDeadline(time.Now().Add(writeTimeout)); err != nil { break } } if bw == nil { bw = acquireWriter(ctx) } if err = writeResponse(ctx, bw); err != nil { break } connectionClose = ctx.Response.Header.ConnectionClose() || ctx.Request.Header.ConnectionClose() if br == nil || connectionClose { err = bw.Flush() releaseWriter(s, bw) bw = nil if err != nil { break } if connectionClose { break } } if ctx.hijackHandler != nil { h := ctx.hijackHandler var hjr io.Reader hjr = c if br != nil { hjr = br br = nil // br may point to ctx.fbr, so do not return ctx into pool. ctx = s.acquireCtx(c) } if bw != nil { err = bw.Flush() releaseWriter(s, bw) bw = nil if err != nil { break } } c.SetReadDeadline(zeroTime) c.SetWriteDeadline(zeroTime) go hijackConnHandler(hjr, c, s, h) err = errHijacked break } currentTime = time.Now() } if br != nil { releaseReader(s, br) } if bw != nil { releaseWriter(s, bw) } s.releaseCtx(ctx) return err }
func (c *hostClient) Attach(req *host.AttachReq, wait bool) (ReadWriteCloser, func() error, error) { data, err := json.Marshal(req) if err != nil { return nil, nil, err } httpReq, err := http.NewRequest("POST", "/attach", bytes.NewBuffer(data)) if err != nil { return nil, nil, err } addrs := c.service.Addrs() if len(addrs) == 0 { return nil, nil, ErrNoServers } conn, err := c.dial("tcp", addrs[0]) if err != nil { return nil, nil, err } clientconn := httputil.NewClientConn(conn, nil) res, err := clientconn.Do(httpReq) if err != nil && err != httputil.ErrPersistEOF { return nil, nil, err } if res.StatusCode != 200 { return nil, nil, fmt.Errorf("cluster: unexpected status %d", res.StatusCode) } var rwc io.ReadWriteCloser var buf *bufio.Reader rwc, buf = clientconn.Hijack() if buf.Buffered() > 0 { rwc = struct { io.Reader writeCloser }{ io.MultiReader(io.LimitReader(buf, int64(buf.Buffered())), rwc), rwc.(writeCloser), } } attachState := make([]byte, 1) if _, err := rwc.Read(attachState); err != nil { rwc.Close() return nil, nil, err } handleState := func() error { switch attachState[0] { case host.AttachSuccess: return nil case host.AttachError: errBytes, err := ioutil.ReadAll(rwc) rwc.Close() if err != nil { return err } return errors.New(string(errBytes)) default: rwc.Close() return fmt.Errorf("cluster: unknown attach state: %d", attachState) } } if attachState[0] == host.AttachWaiting { if !wait { rwc.Close() return nil, nil, ErrWouldWait } return rwc.(ReadWriteCloser), func() error { if _, err := rwc.Read(attachState); err != nil { rwc.Close() return err } return handleState() }, nil } return rwc.(ReadWriteCloser), nil, handleState() }
// Upgrade upgrades the HTTP server connection to the WebSocket protocol. // // Upgrade returns a HandshakeError if the request is not a WebSocket // handshake. Applications should handle errors of this type by replying to the // client with an HTTP response. // // The application is responsible for checking the request origin before // calling Upgrade. An example implementation of the same origin policy is: // // if req.Header.Get("Origin") != "http://"+req.Host { // http.Error(w, "Origin not allowed", 403) // return // } // // Use the responseHeader to specify cookies (Set-Cookie) and the subprotocol // (Sec-WebSocket-Protocol). func Upgrade(resp http.ResponseWriter, requestHeader, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) { if values := requestHeader["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" { return nil, HandshakeError{"websocket: version != 13"} } if !tokenListContainsValue(requestHeader, "Connection", "upgrade") { return nil, HandshakeError{"websocket: connection header != upgrade"} } if !tokenListContainsValue(requestHeader, "Upgrade", "websocket") { return nil, HandshakeError{"websocket: upgrade != websocket"} } var challengeKey string if values := requestHeader["Sec-Websocket-Key"]; len(values) == 0 || values[0] == "" { return nil, HandshakeError{"websocket: key missing or blank"} } else { challengeKey = values[0] } var ( netConn net.Conn br *bufio.Reader err error ) h, ok := resp.(http.Hijacker) if !ok { return nil, errors.New("websocket: response does not implement http.Hijacker") } var rw *bufio.ReadWriter netConn, rw, err = h.Hijack() br = rw.Reader if br.Buffered() > 0 { netConn.Close() return nil, errors.New("websocket: client sent data before handshake is complete.") } c := newConn(netConn, true, readBufSize, writeBufSize) p := c.writeBuf[:0] 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"...) for k, vs := range responseHeader { 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"...) if _, err = netConn.Write(p); err != nil { netConn.Close() return nil, err } return c, nil }