Request returns the specified data segment by reading it from local disk. Implements the protocol.Model interface.
(conn protocol.Connection, req *protocol.Request)
| 1962 | // Request returns the specified data segment by reading it from local disk. |
| 1963 | // Implements the protocol.Model interface. |
| 1964 | func (m *model) Request(conn protocol.Connection, req *protocol.Request) (out protocol.RequestResponse, err error) { |
| 1965 | if req.Size < 0 || req.Offset < 0 { |
| 1966 | return nil, protocol.ErrInvalid |
| 1967 | } |
| 1968 | |
| 1969 | deviceID := conn.DeviceID() |
| 1970 | |
| 1971 | m.mut.RLock() |
| 1972 | folderCfg, ok := m.folderCfgs[req.Folder] |
| 1973 | folderIgnores := m.folderIgnores[req.Folder] |
| 1974 | m.mut.RUnlock() |
| 1975 | if !ok { |
| 1976 | // The folder might be already unpaused in the config, but not yet |
| 1977 | // in the model. |
| 1978 | l.Debugf("Request from %s for file %s in unstarted folder %q", deviceID.Short(), req.Name, req.Folder) |
| 1979 | return nil, protocol.ErrGeneric |
| 1980 | } |
| 1981 | |
| 1982 | if !folderCfg.SharedWith(deviceID) { |
| 1983 | slog.Warn("Request for file in unshared folder", slog.String("folder", req.Folder), deviceID.LogAttr(), slogutil.FilePath(req.Name)) |
| 1984 | return nil, protocol.ErrGeneric |
| 1985 | } |
| 1986 | if folderCfg.Paused { |
| 1987 | l.Debugf("Request from %s for file %s in paused folder %q", deviceID.Short(), req.Name, req.Folder) |
| 1988 | return nil, protocol.ErrGeneric |
| 1989 | } |
| 1990 | |
| 1991 | // Make sure the path is valid and in canonical form |
| 1992 | if name, err := fs.Canonicalize(req.Name); err != nil { |
| 1993 | l.Debugf("Request from %s in folder %q for invalid filename %s", deviceID.Short(), req.Folder, req.Name) |
| 1994 | return nil, protocol.ErrGeneric |
| 1995 | } else { |
| 1996 | req.Name = name |
| 1997 | } |
| 1998 | |
| 1999 | if deviceID != protocol.LocalDeviceID { |
| 2000 | l.Debugf("%v REQ(in): %s: %q / %q o=%d s=%d t=%v", m, deviceID.Short(), req.Folder, req.Name, req.Offset, req.Size, req.FromTemporary) |
| 2001 | } |
| 2002 | |
| 2003 | if fs.IsInternal(req.Name) { |
| 2004 | l.Debugf("%v REQ(in) for internal file: %s: %q / %q o=%d s=%d", m, deviceID.Short(), req.Folder, req.Name, req.Offset, req.Size) |
| 2005 | return nil, protocol.ErrInvalid |
| 2006 | } |
| 2007 | |
| 2008 | if folderIgnores.Match(req.Name).IsIgnored() { |
| 2009 | l.Debugf("%v REQ(in) for ignored file: %s: %q / %q o=%d s=%d", m, deviceID.Short(), req.Folder, req.Name, req.Offset, req.Size) |
| 2010 | return nil, protocol.ErrInvalid |
| 2011 | } |
| 2012 | |
| 2013 | // Restrict parallel requests by connection/device |
| 2014 | |
| 2015 | m.mut.RLock() |
| 2016 | limiter := m.connRequestLimiters[deviceID] |
| 2017 | m.mut.RUnlock() |
| 2018 | |
| 2019 | // The requestResponse releases the bytes to the buffer pool and the |
| 2020 | // limiters when its Close method is called. |
| 2021 | res := newLimitedRequestResponse(req.Size, limiter, m.globalRequestLimiter) |
nothing calls this directly
no test coverage detected