func (c *ServerConnection) handleDelete(user string, req *fosp.Request) *fosp.Response {
	defer timeTrack(time.Now(), "delete request")
	if err := c.server.database.Delete(user, req.URL); err != nil {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
	}
	return fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusNoContent)
}
func (c *ServerConnection) handleWrite(user string, req *fosp.Request) *fosp.Response {
	defer timeTrack(time.Now(), "write request")
	if err := c.server.database.Write(user, req.URL, req.Body); err != nil {
		servConnLog.Warning("Write request failed: " + err.Error())
		return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
	}
	return fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusNoContent)
}
func (c *ServerConnection) handleRead(user string, req *fosp.Request) *fosp.Response {
	defer timeTrack(time.Now(), "read request")
	data, err := c.server.database.Read(user, req.URL)
	if err != nil {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
	}
	resp := fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusOK)
	resp.Body = bytes.NewBuffer(data)
	return resp
}
func (c *ServerConnection) handleCreate(user string, req *fosp.Request) *fosp.Response {
	defer timeTrack(time.Now(), "create request")
	obj := fosp.NewObject()
	if err := json.NewDecoder(req.Body).Decode(obj); err != nil {
		servConnLog.Warning("Unable to decode CREATE body :: %s", err)
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	if err := c.server.database.Create(user, req.URL, obj); err != nil {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
	}
	return fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusCreated)
}
func (c *ServerConnection) handleList(user string, req *fosp.Request) *fosp.Response {
	defer timeTrack(time.Now(), "list request")
	list, err := c.server.database.List(user, req.URL)
	if err != nil {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
	}
	if body, err := json.Marshal(list); err == nil {
		resp := fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusOK)
		resp.Body = bytes.NewBuffer(body)
		return resp
	}
	return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
}
func (c *ServerConnection) handlePatch(user string, req *fosp.Request) *fosp.Response {
	defer timeTrack(time.Now(), "update request")
	var obj fosp.PatchObject
	if err := json.NewDecoder(req.Body).Decode(&obj); err != nil {
		servConnLog.Warning("Unable to decode PATCH body :: %s", err)
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	if err := c.server.database.Patch(user, req.URL, obj); err != nil {
		servConnLog.Warning("Unable to update object %s :: %s", req.URL, err)
		return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
	}
	return fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusNoContent)
}
// BUG: Seems like we are forwarding requests for other servers ...
func (c *ServerConnection) handleRequest(req *fosp.Request) *fosp.Response {
	servConnLog.Debug("Handeling request %#v", req)
	servConnLog.Debug("URL is %s", req.URL)
	if req.URL != nil && req.URL.Host != c.server.Domain() {
		if c.User != "" {
			servConnLog.Info("Try to forward request for user " + c.User)
			if resp, err := c.server.forwardRequest(c.User, req); err == nil {
				servConnLog.Debug("Response is %v+", resp)
				return resp
			}
			return fosp.NewResponse(fosp.FAILED, fosp.StatusBadGateway)
		}
		servConnLog.Fatal("Cannot forward request for non user")
	}
	if req.URL == nil && req.Method != fosp.AUTH {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}

	var user string
	if c.User != "" {
		user = c.User
	} else if reqUser := req.Header.Get("From"); reqUser != "" {
		user = reqUser
	}

	if user == "" && req.Method == fosp.CREATE && req.URL.Path == "/" {
		return c.handleRegister(req)
	}

	switch req.Method {
	case fosp.AUTH:
		return c.handleAuth(req)
	case fosp.GET:
		return c.handleGet(user, req)
	case fosp.CREATE:
		return c.handleCreate(user, req)
	case fosp.PATCH:
		return c.handlePatch(user, req)
	case fosp.LIST:
		return c.handleList(user, req)
	case fosp.DELETE:
		return c.handleDelete(user, req)
	case fosp.READ:
		return c.handleRead(user, req)
	case fosp.WRITE:
		return c.handleWrite(user, req)
	default:
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
}
func (c *ServerConnection) handleGet(user string, req *fosp.Request) *fosp.Response {
	defer timeTrack(time.Now(), "select request")
	object, err := c.server.database.Get(user, req.URL)
	if err != nil {
		if fe, ok := err.(FospError); ok {
			return fosp.NewResponse(fosp.FAILED, fe.Code)
		}
		return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
	}
	body, err := json.Marshal(object)
	if err != nil {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
	}
	resp := fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusOK)
	resp.Body = bytes.NewBuffer(body)
	return resp
}
func (c *ServerConnection) handleRegister(req *fosp.Request) *fosp.Response {
	if req.URL.Host != c.server.Domain() {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	user := req.URL.User.Username() + "@" + req.URL.Host
	obj := fosp.NewObject()
	if err := json.NewDecoder(req.Body).Decode(obj); err != nil {
		servConnLog.Warning("Unable to decode CREATE body :: %s", err)
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	data, ok := obj.Data.(map[string]interface{})
	if !ok {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	opaque, ok := data["password"]
	if !ok {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	password, ok := opaque.(string)
	if !ok {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	if !c.server.database.Register(user, password) {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	return fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusCreated)
}
Пример #10
0
func (c *ServerConnection) handleAuth(req *fosp.Request) *fosp.Response {
	authObj := &AuthenticationObject{Sasl: SaslObject{}}
	err := json.NewDecoder(req.Body).Decode(authObj)
	if err != nil {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	response := ""
	if authObj.Sasl.Mechanism != "" {
		if authObj.Sasl.Mechanism != "PLAIN" {
			return fosp.NewResponse(fosp.FAILED, fosp.StatusNotImplemented)
		}
		c.SaslMechanism = "PLAIN"
		if authObj.Sasl.InitialResponse == nil {
			content := AuthenticationObject{Sasl: SaslObject{Challenge: "Please provide your user name and password"}}
			encoded, err := json.Marshal(content)
			if err != nil {
				return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
			}
			resp := fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusAdditionalDataNeeded)
			resp.Body = bytes.NewBuffer(encoded)
			return resp
		}
		response = *authObj.Sasl.InitialResponse
	} else {
		if c.SaslMechanism != "PLAIN" {
			return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
		}
		if authObj.Sasl.Response == "" {
			return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
		}
		response = authObj.Sasl.Response
	}
	parts := strings.Split(response, "\x00")
	if len(parts) != 3 {
		return fosp.NewResponse(fosp.FAILED, fosp.StatusBadRequest)
	}
	authorizationId := parts[0]
	authenticationId := parts[1]
	password := parts[2]

	if authorizationId != "" && authorizationId != authenticationId {
		content := AuthenticationObject{Sasl: SaslObject{Outcome: "Authorization ID and authentication ID must be the same"}}
		encoded, err := json.Marshal(content)
		if err != nil {
			return fosp.NewResponse(fosp.FAILED, fosp.StatusInternalServerError)
		}
		resp := fosp.NewResponse(fosp.FAILED, fosp.StatusUnauthorized)
		resp.Body = bytes.NewBuffer(encoded)
		return resp
	}
	servConnLog.Debug("Authenticating user %s", authenticationId)
	if c.server.database.Authenticate(authenticationId, password) {
		c.User = authenticationId
		return fosp.NewResponse(fosp.SUCCEEDED, fosp.StatusOK)
	}
	return fosp.NewResponse(fosp.FAILED, fosp.StatusUnauthorized)
}
Пример #11
0
func parseMessage(in io.Reader) (msg fosp.Message, seq uint64, err error) {
	var (
		firstLine []byte
		rawurl    string
		isPrefix  bool
		readerErr error
		fragments [][]byte
		code      int
		msgURL    *url.URL
		reader    *bufio.Reader
		ok        bool
	)
	err = errors.New("Failed to parse message, unknown error")
	if reader, ok = in.(*bufio.Reader); !ok {
		reader = bufio.NewReader(in)
	}
	if firstLine, isPrefix, readerErr = reader.ReadLine(); isPrefix {
		err = errors.New("First line of message is too long")
		return
	} else if readerErr != nil && readerErr != io.EOF {
		err = newNestedError("Reader error", readerErr)
		return
	}
	if fragments = bytes.Split(firstLine, []byte(" ")); len(fragments) < 2 {
		err = errors.New("First line does not consist of at least 2 parts")
		return
	}
	identifier := string(fragments[0])
	switch identifier {
	case fosp.OPTIONS, fosp.AUTH, fosp.GET, fosp.LIST, fosp.CREATE, fosp.PATCH, fosp.DELETE, fosp.READ, fosp.WRITE:
		if len(fragments) != 3 {
			err = errors.New("Request line does not consist of 3 parts")
			return
		}
		rawurl = string(fragments[1])
		if rawurl != "*" {
			rawurl = "fosp://" + string(fragments[1])
			if msgURL, err = url.Parse(rawurl); err != nil {
				err = errors.New("Invalid request URL")
				return
			}
			msgURL.Path = path.Clean(msgURL.Path)
			if msgURL.Path == "." {
				msgURL.Path = "/"
			}
		}
		if seq, err = strconv.ParseUint(string(fragments[2]), 10, 64); err != nil || seq < 1 {
			err = newNestedError("The request sequence number is not valid", err)
			return
		}
		req := fosp.NewRequest(identifier, msgURL)
		if req.Header, err = textproto.NewReader(reader).ReadMIMEHeader(); err != nil && err != io.EOF {
			err = newNestedError("The request header is not valid", err)
			return
		}
		req.Body = reader
		return req, seq, nil
	case fosp.SUCCEEDED, fosp.FAILED:
		if len(fragments) != 3 {
			err = errors.New("Response line does not consist of 3 parts")
			return
		}
		if code, err = strconv.Atoi(string(fragments[1])); err != nil {
			err = newNestedError("Status code is invalid", err)
			return
		}
		if seq, err = strconv.ParseUint(string(fragments[2]), 10, 64); err != nil || seq < 1 {
			err = newNestedError("The response sequence number is not valid", err)
			if seq < 1 {
				err = errors.New("The sequence number is 0")
			}
			return
		}
		resp := fosp.NewResponse(identifier, uint(code))
		if resp.Header, err = textproto.NewReader(reader).ReadMIMEHeader(); err != nil && err != io.EOF {
			err = newNestedError("The response header is not valid", err)
			return
		}
		resp.Body = reader
		return resp, seq, nil
	case fosp.CREATED, fosp.UPDATED, fosp.DELETED:
		if len(fragments) != 2 {
			err = errors.New("Notification line does not consist of 2 parts")
			return
		}
		rawurl = string(fragments[1])
		if rawurl != "*" {
			rawurl = "fosp://" + string(fragments[1])
			if msgURL, err = url.Parse(rawurl); err != nil {
				err = errors.New("Invalid request URL")
				return
			}
			msgURL.Path = path.Clean(msgURL.Path)
			if msgURL.Path == "." {
				msgURL.Path = "/"
			}
		}
		evt := fosp.NewNotification(identifier, msgURL)
		if evt.Header, err = textproto.NewReader(reader).ReadMIMEHeader(); err != nil && err != io.EOF {
			err = newNestedError("The notification header is not valid", err)
			return
		}
		evt.Body = reader
		return evt, seq, nil
	default:
		err = errors.New("Unrecognized identifier " + identifier)
		return
	}
}