For open/opendir requests we create a new handle and close it
when the client sends an SSH_FXP_CLOSE but if we return an error the
client will never send the close packet so we have to close the handle
ourselves
we need to add a case for this packet inside the packet worker otherwise
it will be handled in hasHandle case and it will become a "Put" request.
Client side if a Truncate request is called on the open file we should
send a FSETSTAT packet, the request is on the handle, and not a SETSTAT
packet that should be used for paths and not for handle.
after processing a packet we keep in memory the allocated slices and we reuse
them for new packets.
Slices are allocated in:
- recvPacket
- when we receive a sshFxpReadPacket (downloads)
The allocated slices have a fixed size = maxMsgLength.
Allocated slices are referenced to the request order id and are marked for reuse
after a request is served in maybeSendPackets.
The allocator is added to the packetManager struct and it is cleaned at the end
of the Serve() function.
This allocation mode is optional and disabled by default
Add an optional interface that readerAt and writerAt can implement
to be notified about the error causing Serve() to exit with the
request still open.
Implement the TransferError interface in request-example.
This way we can run the request server example in debug mode, for example:
cd examples/request-server
go run -tags debug main.go
simulate a connection error killing an sftp client while uploading/downloading
and see the debug log that shows that the error is correctly notifyed
Fixes#306
Previously if a client makes an unsupported operation,
like a POSIX rename, it would exit the server.
Both support POSIX rename, and do not abort the connection
if there is an unsupported operation is made by the client.
When fstat is called it now uses the handle to get the opened request,
pulls the filepath from that and creates a new request for the fstat
call. This eliminates the need to change the Method on the request
object and furthers the goal of eliminating post-creation mutation of
the request object to open up the possibility to eliminate or at least
reduce the use of the global request lock.
Just like with files, the call to the hander to create the Lister is
done when the OPENDIR packet is received. This eliminates the need for
the lock in the filelist() method and opens the path for eliminating
more locks.
Testing feasibility of creating the reader/writer when first receiving
the Open packet instead of waiting for the Get/Put.
This work is meant to make the Request locks easier to manage and
ultimately reducing/eliminating them as much as possible.
Previous code used the request ids to do ordering. This worked until a
client came along that used un-ordered request ids. This reworks the
ordering to use an internal counter (per session) to order all packets
ensuring that responses are sent in the same order as the requests were
received.
Fixes#260
Instead of accepting a more general type and then asserting it to the
proper type, just take the proper type as the argument.
Also clean up some of the use of it where it checked old direct sending
code's return error (error is now always nil).
PR #257 fixes the issue with running Stat and Readdir on the same
Request. Thus we no longer need to close and recreate the Request
when handling an Opendir call.
The initial Opendir packet is supposed to repond with an error status if
the directory wasn't found. It was just returning a handle without
checking, now it does a Stat on the path and only returns the handle if
the Stat is successful and it indicates it is a directory, otherwise it
returns an error.
Create a master Context in the per-session ReqeustServer.Serve method
that is then used as the parent for all Context's created in that
server. Its cancelFunc is then always called when Serve exits. This is
in line which out the http.serve code works.
Each Request gets a child WithCancel context created in the
requestFromPacket call. This Context is still closed on request.close().
Recent refactoring has eliminated the need for Fstat and Fsetstat (stat
operations on file handle instead of path)to be special cased. They will
now just work with the normal case for any packet with a file handle.
Fixes#217, where the path cleaning code was mangling the volume name on
windows; ie. "c:/some/path" was turned into "/c:/some/path". Using the
filepath.IsAbs() (vs path.IsAbs()) uses OS specific tests and fixes
this.
This goes against strict POSIX paths, but this used to work and fixing
it breaks nothing on other platforms. And we have still standardized on
POSIX style delimiters.
When the SSH_FXP_OPEN packet has the SSH_FXF_CREAT pflag set the file
should get created even if no data is sent. We do this by having the
Open method call through to the FilePut Handler with empty packet data.
Fixes#214
In #192 we normalized all Request use to have pointer receivers. This
simplified reasoning and allowed for a simpler Request struct. This
change completes that work by eliminating the need for the
state/stackLock pointers and also removes the need for a new Request
each packet, reducing the pressure on the GC.
The main bit is that the RequestServer.openRequests[] map now stores Request
pointers and it only creates new Requests (replacing the mapped entry) when the
Method changes. It never updates/modifies an existing Request and the packet to
Method mapping is now all in place place (requestMethod).
Fix#207
The primary issue of the resolved ticket was path cleaning code returned
the path of '/.' instead of '/'.
We also reviewed and clarified the use of filepath/path and how OS
specific paths are handled in the server code. All paths are converted
to POSIX paths as they come into the server. They are then POSIX paths
for all internal operations.
Request object had a packet channel where it stored packets for
read/write/readdir handling. It was required in an earlier version of
the code (that was refactored before merging) and never got cleaned up.
This removes that channel and just passes the packet through the methods
instead. This is much simpler and would have eliminated the chance of
issue #195. It also looks like it should allow for a few more
simplifications as well.