コード例 #1
0
ファイル: track_test.go プロジェクト: wunderlist/hamustro
// Returns jobs from a collection (used for expected output)
func GetJobsFromCollection(collection *payload.Collection) []*EventAction {
	var jobs []*EventAction
	for _, payload := range collection.GetPayloads() {
		jobs = append(jobs, &EventAction{dialects.NewEvent(collection, payload), 1})
	}
	return jobs
}
コード例 #2
0
ファイル: track.go プロジェクト: wunderlist/hamustro
// Controller for `/api/v1/track`
func TrackHandler(w http.ResponseWriter, r *http.Request) {
	// Do not accept new events while the server is shutting down.
	if isTerminating {
		BroadcastError(w, "Server is currenly shutting down", http.StatusServiceUnavailable)
		return
	}

	// Ignore not POST messages.
	if r.Method != "POST" {
		BroadcastError(w, "Sending method is not POST", http.StatusMethodNotAllowed)
		return
	}

	// Checks that the client want to send signature or not
	definedSignature := r.Header.Get("X-Hamustro-Time") != "" || r.Header.Get("X-Hamustro-Signature") != ""

	// If the client did not send time, we ignore
	if (signatureRequired || definedSignature) && r.Header.Get("X-Hamustro-Time") == "" {
		BroadcastError(w, "X-Hamustro-Time header is missing", http.StatusMethodNotAllowed)
		return
	}

	// If the client did not send signature of the message, we ignore
	if (signatureRequired || definedSignature) && r.Header.Get("X-Hamustro-Signature") == "" {
		BroadcastError(w, "X-Hamustro-Signature header is missing", http.StatusMethodNotAllowed)
		return
	}

	// Read the requests body into a variable.
	body, _ := ioutil.ReadAll(r.Body)

	// Calculate the request's signature
	if (signatureRequired || definedSignature) && r.Header.Get("X-Hamustro-Signature") != GetSignature(body, r.Header.Get("X-Hamustro-Time")) {
		BroadcastError(w, "X-Hamustro-Signature header is invalid", http.StatusMethodNotAllowed)
		return
	}

	collection := &payload.Collection{}
	contentType, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
	switch contentType {
	case "application/json":
		if err := jsonpb.Unmarshal(bytes.NewBuffer(body), collection); err != nil {
			BroadcastError(w, fmt.Sprintf("Unmarshaling json collection is failed: %s", err.Error()), http.StatusBadRequest)
			return
		}
		if !collection.IsValid() {
			BroadcastError(w, fmt.Sprintf("Unmarshaled json collection is failed: required field not set"), http.StatusBadRequest)
			return
		}
	case "application/protobuf":
		if err := proto.Unmarshal(body, collection); err != nil {
			BroadcastError(w, fmt.Sprintf("Unmarshaling protobuf is failed: %s", err.Error()), http.StatusBadRequest)
			return
		}
	default:
		BroadcastError(w, "Unsupported or missing Content-Type", http.StatusBadRequest)
		return
	}

	// Checks the session information
	if GetSession(collection) != collection.GetSession() {
		BroadcastError(w, "Collection's session attribute is invalid", http.StatusBadRequest)
		return
	}

	// Stop if no payload information was received
	if !collection.HasPayloads() {
		w.WriteHeader(http.StatusNoContent)
		return
	}

	// Creates a Job and put into the JobQueue for processing.
	for _, payload := range collection.GetPayloads() {
		event := dialects.NewEvent(collection, payload)
		if config.IsMaskedIP() {
			event.TruncateIPv4LastOctet()
		}
		action := EventAction{event, 1}
		jobQueue <- &action
	}

	// Returns with 200.
	w.WriteHeader(http.StatusOK)
}