Exemple #1
0
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
}
Exemple #3
0
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
}
Exemple #5
0
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
}
Exemple #6
0
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
}
Exemple #7
0
func fullRuneBuffered(br *bufio.Reader) bool {
	n := br.Buffered()
	buf, err := br.Peek(n)
	if err != nil {
		return false
	}
	return utf8.FullRune(buf)
}
Exemple #8
0
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)
}
Exemple #9
0
// 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
}
Exemple #10
0
// 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
}
Exemple #11
0
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
}
Exemple #12
0
// 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
}
Exemple #13
0
// 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
	}
}
Exemple #14
0
// 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
	}
}
Exemple #15
0
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())
}
Exemple #16
0
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
}
Exemple #17
0
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
}
Exemple #18
0
// 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
}
Exemple #19
0
// 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
}
Exemple #20
0
//当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
}
Exemple #21
0
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
}
Exemple #23
0
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
		}
	}
}
Exemple #24
0
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
}
Exemple #25
0
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
}
Exemple #26
0
// 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
}
Exemple #27
0
// 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
}
Exemple #28
0
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
}
Exemple #29
0
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()
}
Exemple #30
0
// 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
}