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) }
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) }
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 } }