Hi Matthias, We're doing the same, using sshd-core-1.2.0: we implemented our own FileChannel and throw an IOException in implCloseChannel when the uploaded file (in our case an XML-file) is not valid. This works as expected. I haven't tried 2.0.0, but might it be a bug in the new implementation?
Best, Dennis On Mon, 10 Sep 2018 at 13:06, Matthias Hjalmarsson <matth...@yacc.se> wrote: > Hi, > > as a short backstory, we are looking at providing a SFTP endpoint for > legacy clients where they can upload files to a single root/default > directory and have them dynamically forwarded internally correctly. For > this purpose, all operations / file systems will be purely virtual. Even > listing of files won't be supported, just an upload operation (the root > directory will always appear to be empty). > > When a file is finished uploaded (into server memory), we want to push the > file to an internal service. For the sake of this question, let's just say > it's a simple REST service that we push to. Workflow is basically: > > 1) User connects and is authenticated > 2) Root directory appears to be empty > 3) PUT <some file> > 4) File is uploaded to server into server's memory > 5) When upload is finished, server pushes file to its correct final > destination > 6) Client receives OK > > We have a working proof-of-concept of this that works really well. To do > this, we implemented a minimal NIO FileSystem. > > The problem we are having is when [5] fails. The service we are pushing to > might be down, and then we want the client to get an error as well (= > please try again later). However, the problem is that we can not get the > server to report anything but success which means the client will think it > went through and the server is left with a file it couldn't process. We > don't want to have an internal retry-functionality inside the server but to > have the whole use-case synchronized. > > To get back to the question, I have a hard time know if this is due to > incorrect usage of NIO FileSystem from my part, or if perhaps SSHD doesn't > support this usecase. > > Our basic strategy is to eventually create a custom implementation of > FileChannel when FileSystemProvider#newFileChannel is called. Via debugging > inspection this appears to be callback we get on our FileSystemProvider > when an upload is initiated. This implementation handles the write() > operations to write the bytes into a local byte[], and then when eventually > UploadFileChannel#implCloseChannel() is called the byte[] is pushed. > > implCloseChannel() can throw an IOException, but this doesn't seem to > matter. Regardless, from the client's point-of-view it doesn't matter if > this call is successful or not. Looking at the code, I can step in > SSHD-SFTP into: > > Here, it seems like SSH_FXP_CLOSE would be sent if the closing of the > handle is not successful. I'm not sure if that would be the proper way of > reporting problems to the client, but regardless, it looks like this code > path isn't used. Because doClose(int, String) is called in the try-block, > and this code itself catch IOException in order to make callback to > listener. Should perhaps IOException be rethrown there? > > protected void doClose(Buffer buffer, int id) throws IOException { > String handle = buffer.getString(); > try { > doClose(id, handle); > } catch (IOException | RuntimeException e) { > sendStatus(prepareReply(buffer), id, e, SftpConstants.SSH_FXP_CLOSE, > handle); > return; > } > > sendStatus(prepareReply(buffer), id, SftpConstants.SSH_FX_OK, "", ""); > } > @Override > protected void doClose(int id, String handle) throws IOException { > Handle h = handles.remove(handle); > ServerSession session = getServerSession(); > if (log.isDebugEnabled()) { > log.debug("doClose({})[id={}] SSH_FXP_CLOSE (handle={}[{}])", > session, id, handle, h); > } > > Handle nodeHandle = validateHandle(handle, h, Handle.class); > SftpEventListener listener = getSftpEventListenerProxy(); > try { > listener.closing(session, handle, nodeHandle); > nodeHandle.close(); > listener.closed(session, handle, nodeHandle, null); > } catch (IOException | RuntimeException e) { > listener.closed(session, handle, nodeHandle, e); > } > } > > Or am I going about this the wrong way? I'm using apache-sshd-2.0.0. > > Thanks in advance! > > // Matthias >