Exemple #1
0
// ReqReplyStreamChan tests a request-reply type of com over a stream.
func (*Handler) ReqReplyStreamChan(stream api.Stream, name string) error {
	for {
		var msg string
		err := stream.Receive(&msg)
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Printf("Error: %v\n", err)
			return err
		}
		err = stream.Send(name + ":" + msg + " received")
		if err != nil {
			log.Printf("Error: %v\n", err)
			return err
		}
	}
	return stream.Close()
}
Exemple #2
0
// ServeHTTP serves individual HTTP requests.
func (server *Server) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	origin := req.Header.Get("Origin")
	if origin != "" {
		// TODO: Perhaps a lever.json config param could restrict origin
		//       to prevent CSRF.
		resp.Header().Set("Access-Control-Allow-Origin", origin)
		resp.Header().Set(
			"Access-Control-Allow-Headers",
			"Accept, Content-Type, Content-Length, Accept-Encoding, "+
				"X-CSRF-Token, Authorization")
	}
	if req.Method == "OPTIONS" {
		resp.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
		resp.WriteHeader(http.StatusOK)
		return
	}
	if req.Method != "POST" {
		resp.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	leverURLStr := fmt.Sprintf("lever://%s%s", req.Host, req.URL.Path)
	leverURL, err := core.ParseLeverURL(leverURLStr)
	if err != nil {
		logger.WithFields("err", err).Debug("Error parsing Lever URL")
		resp.WriteHeader(http.StatusBadRequest)
		return
	}

	queryValues, err := url.ParseQuery(req.URL.RawQuery)
	if err != nil {
		logger.WithFields("err", err).Debug("Error parsing URL query")
		resp.WriteHeader(http.StatusBadRequest)
		return
	}
	forceEnv := queryValues.Get("forceenv")
	if forceEnv != "" {
		leverURL.Environment = forceEnv
	}
	leverURLStr = leverURL.String()

	reader := bufferedReaderPool.Get().(*bufio.Reader)
	reader.Reset(req.Body)
	defer bufferedReaderPool.Put(reader)
	defer req.Body.Close()
	if leverapi.IsChanMethod(leverURL.Method) {
		// TODO: Byte args not supported. Any way to support that?
		//       How to delimit args from rest?
		done := false
		var line []byte
		line, err = reader.ReadBytes('\n')
		if err != nil {
			if err == io.EOF {
				done = true
			} else {
				logger.WithFields("err", err).Error("Read error")
				return
			}
		}
		if len(line) == 0 {
			resp.WriteHeader(http.StatusBadRequest)
			return
		}
		var args []interface{}
		err = json.Unmarshal(line, &args)
		if err != nil {
			resp.WriteHeader(http.StatusBadRequest)
			logger.WithFields("err", err).Debug("Malformed JSON")
			return
		}
		var stream leverapi.Stream
		stream, err = server.leverClient.InvokeChanURL(leverURLStr, args...)
		if err != nil {
			resp.WriteHeader(http.StatusInternalServerError)
			logger.WithFields("err", err).Error("InvokeChanURL error")
			return
		}
		errCh := make(chan bool)
		workerDoneCh := make(chan struct{})
		go replyStreamWorker(stream, resp, errCh, workerDoneCh)
		if req.Header.Get("Content-Type") == "application/json" {
			for !done {
				line, err = reader.ReadBytes('\n')
				if err != nil {
					if err == io.EOF {
						done = true
					} else {
						logger.WithFields("err", err).Error("Read error")
						errCh <- true
						<-workerDoneCh
						return
					}
				}
				if len(line) > 0 {
					var msg interface{}
					err = json.Unmarshal(line, &msg)
					if err != nil {
						logger.WithFields("err", err).Debug("Malformed JSON")
						errCh <- true
						<-workerDoneCh
						return
					}
					stream.Send(msg)
				}
			}
		} else {
			for !done {
				buffer := bufferPool.Get().([]byte)
				defer bufferPool.Put(buffer)
				var size int
				size, err = reader.Read(buffer)
				if err != nil {
					if err == io.EOF {
						done = true
					}
					logger.WithFields("err", err).Error("Read error")
					errCh <- true
					<-workerDoneCh
					return
				}
				msg := buffer[:size]
				stream.Send(msg)
			}
		}
		err = stream.Close()
		if err != nil {
			logger.WithFields("err", err).Debug(
				"Stream close error")
			errCh <- true
			<-workerDoneCh
			return
		}
		errCh <- false
		<-workerDoneCh
	} else {
		buffer := bufferPool.Get().([]byte)
		defer bufferPool.Put(buffer)
		var size int
		size, err = io.ReadFull(reader, buffer)
		if err != nil {
			if err != io.EOF && err != io.ErrUnexpectedEOF {
				logger.WithFields("err", err).Error("Read error")
				return
			}
		}
		if size == maxNonChanRequestSize &&
			err != io.EOF &&
			err != io.ErrUnexpectedEOF {
			resp.WriteHeader(http.StatusBadRequest)
			_, err = resp.Write([]byte("\"Exceeded maximum request size\""))
			if err != nil {
				logger.WithFields("err", err).Debug("Write error")
			}
			return
		}
		var args []interface{}
		contentType := req.Header.Get("Content-Type")
		contentTypeSplit := strings.Split(contentType, ";")
		switch contentTypeSplit[0] {
		case "application/json":
			err = json.Unmarshal(buffer[:size], &args)
			if err != nil {
				resp.WriteHeader(http.StatusBadRequest)
				logger.WithFields("err", err).Debug("JSON unmarshal error")
				return
			}
		case "application/x-www-form-urlencoded":
			// TODO
			resp.WriteHeader(http.StatusBadRequest)
			logger.WithFields("contentType", contentType).Error(
				"Content type not yet supported")
			return
		default:
			args = make([]interface{}, 1)
			args[0] = buffer[:size]
		}
		var reply interface{}
		err = server.leverClient.InvokeURL(&reply, leverURLStr, args...)
		if err != nil {
			resp.WriteHeader(http.StatusInternalServerError)
			remoteErr, ok := err.(*leverapi.RemoteError)
			if ok {
				reply = remoteErr.Err
			} else {
				remoteByteErr, ok := err.(*leverapi.RemoteByteError)
				if ok {
					reply = remoteByteErr.Err
				} else {
					logger.WithFields("err", err).Error("Internal Lever error")
					return
				}
			}
		} else {
			resp.WriteHeader(http.StatusOK)
		}

		err = writeReply(resp, reply)
		if err != nil {
			logger.WithFields("err", err).Error("Writing reply failed")
			return
		}
	}
}