session_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package ssh
  5. // Session tests.
  6. import (
  7. "bytes"
  8. crypto_rand "crypto/rand"
  9. "io"
  10. "io/ioutil"
  11. "math/rand"
  12. "net"
  13. "testing"
  14. "code.google.com/p/go.crypto/ssh/terminal"
  15. )
  16. type serverType func(*serverChan, *testing.T)
  17. // dial constructs a new test server and returns a *ClientConn.
  18. func dial(handler serverType, t *testing.T) *ClientConn {
  19. pw := password("tiger")
  20. serverConfig.PasswordCallback = func(conn *ServerConn, user, pass string) bool {
  21. return user == "testuser" && pass == string(pw)
  22. }
  23. serverConfig.PublicKeyCallback = nil
  24. l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
  25. if err != nil {
  26. t.Fatalf("unable to listen: %v", err)
  27. }
  28. go func() {
  29. defer l.Close()
  30. conn, err := l.Accept()
  31. if err != nil {
  32. t.Errorf("Unable to accept: %v", err)
  33. return
  34. }
  35. defer conn.Close()
  36. if err := conn.Handshake(); err != nil {
  37. t.Errorf("Unable to handshake: %v", err)
  38. return
  39. }
  40. done := make(chan struct{})
  41. for {
  42. ch, err := conn.Accept()
  43. if err == io.EOF || err == io.ErrUnexpectedEOF {
  44. return
  45. }
  46. // We sometimes get ECONNRESET rather than EOF.
  47. if _, ok := err.(*net.OpError); ok {
  48. return
  49. }
  50. if err != nil {
  51. t.Errorf("Unable to accept incoming channel request: %v", err)
  52. return
  53. }
  54. if ch.ChannelType() != "session" {
  55. ch.Reject(UnknownChannelType, "unknown channel type")
  56. continue
  57. }
  58. ch.Accept()
  59. go func() {
  60. defer close(done)
  61. handler(ch.(*serverChan), t)
  62. }()
  63. }
  64. <-done
  65. }()
  66. config := &ClientConfig{
  67. User: "testuser",
  68. Auth: []ClientAuth{
  69. ClientAuthPassword(pw),
  70. },
  71. }
  72. c, err := Dial("tcp", l.Addr().String(), config)
  73. if err != nil {
  74. t.Fatalf("unable to dial remote side: %v", err)
  75. }
  76. return c
  77. }
  78. // Test a simple string is returned to session.Stdout.
  79. func TestSessionShell(t *testing.T) {
  80. conn := dial(shellHandler, t)
  81. defer conn.Close()
  82. session, err := conn.NewSession()
  83. if err != nil {
  84. t.Fatalf("Unable to request new session: %v", err)
  85. }
  86. defer session.Close()
  87. stdout := new(bytes.Buffer)
  88. session.Stdout = stdout
  89. if err := session.Shell(); err != nil {
  90. t.Fatalf("Unable to execute command: %s", err)
  91. }
  92. if err := session.Wait(); err != nil {
  93. t.Fatalf("Remote command did not exit cleanly: %v", err)
  94. }
  95. actual := stdout.String()
  96. if actual != "golang" {
  97. t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
  98. }
  99. }
  100. // TODO(dfc) add support for Std{in,err}Pipe when the Server supports it.
  101. // Test a simple string is returned via StdoutPipe.
  102. func TestSessionStdoutPipe(t *testing.T) {
  103. conn := dial(shellHandler, t)
  104. defer conn.Close()
  105. session, err := conn.NewSession()
  106. if err != nil {
  107. t.Fatalf("Unable to request new session: %v", err)
  108. }
  109. defer session.Close()
  110. stdout, err := session.StdoutPipe()
  111. if err != nil {
  112. t.Fatalf("Unable to request StdoutPipe(): %v", err)
  113. }
  114. var buf bytes.Buffer
  115. if err := session.Shell(); err != nil {
  116. t.Fatalf("Unable to execute command: %v", err)
  117. }
  118. done := make(chan bool, 1)
  119. go func() {
  120. if _, err := io.Copy(&buf, stdout); err != nil {
  121. t.Errorf("Copy of stdout failed: %v", err)
  122. }
  123. done <- true
  124. }()
  125. if err := session.Wait(); err != nil {
  126. t.Fatalf("Remote command did not exit cleanly: %v", err)
  127. }
  128. <-done
  129. actual := buf.String()
  130. if actual != "golang" {
  131. t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
  132. }
  133. }
  134. // Test non-0 exit status is returned correctly.
  135. func TestExitStatusNonZero(t *testing.T) {
  136. conn := dial(exitStatusNonZeroHandler, t)
  137. defer conn.Close()
  138. session, err := conn.NewSession()
  139. if err != nil {
  140. t.Fatalf("Unable to request new session: %v", err)
  141. }
  142. defer session.Close()
  143. if err := session.Shell(); err != nil {
  144. t.Fatalf("Unable to execute command: %v", err)
  145. }
  146. err = session.Wait()
  147. if err == nil {
  148. t.Fatalf("expected command to fail but it didn't")
  149. }
  150. e, ok := err.(*ExitError)
  151. if !ok {
  152. t.Fatalf("expected *ExitError but got %T", err)
  153. }
  154. if e.ExitStatus() != 15 {
  155. t.Fatalf("expected command to exit with 15 but got %v", e.ExitStatus())
  156. }
  157. }
  158. // Test 0 exit status is returned correctly.
  159. func TestExitStatusZero(t *testing.T) {
  160. conn := dial(exitStatusZeroHandler, t)
  161. defer conn.Close()
  162. session, err := conn.NewSession()
  163. if err != nil {
  164. t.Fatalf("Unable to request new session: %v", err)
  165. }
  166. defer session.Close()
  167. if err := session.Shell(); err != nil {
  168. t.Fatalf("Unable to execute command: %v", err)
  169. }
  170. err = session.Wait()
  171. if err != nil {
  172. t.Fatalf("expected nil but got %v", err)
  173. }
  174. }
  175. // Test exit signal and status are both returned correctly.
  176. func TestExitSignalAndStatus(t *testing.T) {
  177. conn := dial(exitSignalAndStatusHandler, t)
  178. defer conn.Close()
  179. session, err := conn.NewSession()
  180. if err != nil {
  181. t.Fatalf("Unable to request new session: %v", err)
  182. }
  183. defer session.Close()
  184. if err := session.Shell(); err != nil {
  185. t.Fatalf("Unable to execute command: %v", err)
  186. }
  187. err = session.Wait()
  188. if err == nil {
  189. t.Fatalf("expected command to fail but it didn't")
  190. }
  191. e, ok := err.(*ExitError)
  192. if !ok {
  193. t.Fatalf("expected *ExitError but got %T", err)
  194. }
  195. if e.Signal() != "TERM" || e.ExitStatus() != 15 {
  196. t.Fatalf("expected command to exit with signal TERM and status 15 but got signal %s and status %v", e.Signal(), e.ExitStatus())
  197. }
  198. }
  199. // Test exit signal and status are both returned correctly.
  200. func TestKnownExitSignalOnly(t *testing.T) {
  201. conn := dial(exitSignalHandler, t)
  202. defer conn.Close()
  203. session, err := conn.NewSession()
  204. if err != nil {
  205. t.Fatalf("Unable to request new session: %v", err)
  206. }
  207. defer session.Close()
  208. if err := session.Shell(); err != nil {
  209. t.Fatalf("Unable to execute command: %v", err)
  210. }
  211. err = session.Wait()
  212. if err == nil {
  213. t.Fatalf("expected command to fail but it didn't")
  214. }
  215. e, ok := err.(*ExitError)
  216. if !ok {
  217. t.Fatalf("expected *ExitError but got %T", err)
  218. }
  219. if e.Signal() != "TERM" || e.ExitStatus() != 143 {
  220. t.Fatalf("expected command to exit with signal TERM and status 143 but got signal %s and status %v", e.Signal(), e.ExitStatus())
  221. }
  222. }
  223. // Test exit signal and status are both returned correctly.
  224. func TestUnknownExitSignal(t *testing.T) {
  225. conn := dial(exitSignalUnknownHandler, t)
  226. defer conn.Close()
  227. session, err := conn.NewSession()
  228. if err != nil {
  229. t.Fatalf("Unable to request new session: %v", err)
  230. }
  231. defer session.Close()
  232. if err := session.Shell(); err != nil {
  233. t.Fatalf("Unable to execute command: %v", err)
  234. }
  235. err = session.Wait()
  236. if err == nil {
  237. t.Fatalf("expected command to fail but it didn't")
  238. }
  239. e, ok := err.(*ExitError)
  240. if !ok {
  241. t.Fatalf("expected *ExitError but got %T", err)
  242. }
  243. if e.Signal() != "SYS" || e.ExitStatus() != 128 {
  244. t.Fatalf("expected command to exit with signal SYS and status 128 but got signal %s and status %v", e.Signal(), e.ExitStatus())
  245. }
  246. }
  247. // Test WaitMsg is not returned if the channel closes abruptly.
  248. func TestExitWithoutStatusOrSignal(t *testing.T) {
  249. conn := dial(exitWithoutSignalOrStatus, t)
  250. defer conn.Close()
  251. session, err := conn.NewSession()
  252. if err != nil {
  253. t.Fatalf("Unable to request new session: %v", err)
  254. }
  255. defer session.Close()
  256. if err := session.Shell(); err != nil {
  257. t.Fatalf("Unable to execute command: %v", err)
  258. }
  259. err = session.Wait()
  260. if err == nil {
  261. t.Fatalf("expected command to fail but it didn't")
  262. }
  263. _, ok := err.(*ExitError)
  264. if ok {
  265. // you can't actually test for errors.errorString
  266. // because it's not exported.
  267. t.Fatalf("expected *errorString but got %T", err)
  268. }
  269. }
  270. func TestInvalidServerMessage(t *testing.T) {
  271. conn := dial(sendInvalidRecord, t)
  272. defer conn.Close()
  273. session, err := conn.NewSession()
  274. if err != nil {
  275. t.Fatalf("Unable to request new session: %v", err)
  276. }
  277. // Make sure that we closed all the clientChans when the connection
  278. // failed.
  279. session.wait()
  280. defer session.Close()
  281. }
  282. // In the wild some clients (and servers) send zero sized window updates.
  283. // Test that the client can continue after receiving a zero sized update.
  284. func TestClientZeroWindowAdjust(t *testing.T) {
  285. conn := dial(sendZeroWindowAdjust, t)
  286. defer conn.Close()
  287. session, err := conn.NewSession()
  288. if err != nil {
  289. t.Fatalf("Unable to request new session: %v", err)
  290. }
  291. defer session.Close()
  292. if err := session.Shell(); err != nil {
  293. t.Fatalf("Unable to execute command: %v", err)
  294. }
  295. err = session.Wait()
  296. if err != nil {
  297. t.Fatalf("expected nil but got %v", err)
  298. }
  299. }
  300. // In the wild some clients (and servers) send zero sized window updates.
  301. // Test that the server can continue after receiving a zero size update.
  302. func TestServerZeroWindowAdjust(t *testing.T) {
  303. conn := dial(exitStatusZeroHandler, t)
  304. defer conn.Close()
  305. session, err := conn.NewSession()
  306. if err != nil {
  307. t.Fatalf("Unable to request new session: %v", err)
  308. }
  309. defer session.Close()
  310. if err := session.Shell(); err != nil {
  311. t.Fatalf("Unable to execute command: %v", err)
  312. }
  313. // send a bogus zero sized window update
  314. session.clientChan.sendWindowAdj(0)
  315. err = session.Wait()
  316. if err != nil {
  317. t.Fatalf("expected nil but got %v", err)
  318. }
  319. }
  320. // Verify that the client never sends a packet larger than maxpacket.
  321. func TestClientStdinRespectsMaxPacketSize(t *testing.T) {
  322. conn := dial(discardHandler, t)
  323. defer conn.Close()
  324. session, err := conn.NewSession()
  325. if err != nil {
  326. t.Fatalf("failed to request new session: %v", err)
  327. }
  328. defer session.Close()
  329. stdin, err := session.StdinPipe()
  330. if err != nil {
  331. t.Fatalf("failed to obtain stdinpipe: %v", err)
  332. }
  333. const size = 100 * 1000
  334. for i := 0; i < 10; i++ {
  335. n, err := stdin.Write(make([]byte, size))
  336. if n != size || err != nil {
  337. t.Fatalf("failed to write: %d, %v", n, err)
  338. }
  339. }
  340. }
  341. // Verify that the client never accepts a packet larger than maxpacket.
  342. func TestServerStdoutRespectsMaxPacketSize(t *testing.T) {
  343. conn := dial(largeSendHandler, t)
  344. defer conn.Close()
  345. session, err := conn.NewSession()
  346. if err != nil {
  347. t.Fatalf("Unable to request new session: %v", err)
  348. }
  349. defer session.Close()
  350. out, err := session.StdoutPipe()
  351. if err != nil {
  352. t.Fatalf("Unable to connect to Stdout: %v", err)
  353. }
  354. if err := session.Shell(); err != nil {
  355. t.Fatalf("Unable to execute command: %v", err)
  356. }
  357. if _, err := ioutil.ReadAll(out); err != nil {
  358. t.Fatalf("failed to read: %v", err)
  359. }
  360. }
  361. func TestClientCannotSendAfterEOF(t *testing.T) {
  362. conn := dial(exitWithoutSignalOrStatus, t)
  363. defer conn.Close()
  364. session, err := conn.NewSession()
  365. if err != nil {
  366. t.Fatalf("Unable to request new session: %v", err)
  367. }
  368. defer session.Close()
  369. in, err := session.StdinPipe()
  370. if err != nil {
  371. t.Fatalf("Unable to connect channel stdin: %v", err)
  372. }
  373. if err := session.Shell(); err != nil {
  374. t.Fatalf("Unable to execute command: %v", err)
  375. }
  376. if err := in.Close(); err != nil {
  377. t.Fatalf("Unable to close stdin: %v", err)
  378. }
  379. if _, err := in.Write([]byte("foo")); err == nil {
  380. t.Fatalf("Session write should fail")
  381. }
  382. }
  383. func TestClientCannotSendAfterClose(t *testing.T) {
  384. conn := dial(exitWithoutSignalOrStatus, t)
  385. defer conn.Close()
  386. session, err := conn.NewSession()
  387. if err != nil {
  388. t.Fatalf("Unable to request new session: %v", err)
  389. }
  390. defer session.Close()
  391. in, err := session.StdinPipe()
  392. if err != nil {
  393. t.Fatalf("Unable to connect channel stdin: %v", err)
  394. }
  395. if err := session.Shell(); err != nil {
  396. t.Fatalf("Unable to execute command: %v", err)
  397. }
  398. // close underlying channel
  399. if err := session.channel.Close(); err != nil {
  400. t.Fatalf("Unable to close session: %v", err)
  401. }
  402. if _, err := in.Write([]byte("foo")); err == nil {
  403. t.Fatalf("Session write should fail")
  404. }
  405. }
  406. // windowTestBytes is the number of bytes that we'll send to the SSH server.
  407. const windowTestBytes = 16000 * 200
  408. // TestServerWindow writes random data to the server. The server is expected to echo
  409. // the same data back, which is compared against the original.
  410. func TestServerWindow(t *testing.T) {
  411. origBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
  412. io.CopyN(origBuf, crypto_rand.Reader, windowTestBytes)
  413. origBytes := origBuf.Bytes()
  414. conn := dial(echoHandler, t)
  415. defer conn.Close()
  416. session, err := conn.NewSession()
  417. if err != nil {
  418. t.Fatal(err)
  419. }
  420. defer session.Close()
  421. result := make(chan []byte)
  422. go func() {
  423. defer close(result)
  424. echoedBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
  425. serverStdout, err := session.StdoutPipe()
  426. if err != nil {
  427. t.Errorf("StdoutPipe failed: %v", err)
  428. return
  429. }
  430. n, err := copyNRandomly("stdout", echoedBuf, serverStdout, windowTestBytes)
  431. if err != nil && err != io.EOF {
  432. t.Errorf("Read only %d bytes from server, expected %d: %v", n, windowTestBytes, err)
  433. }
  434. result <- echoedBuf.Bytes()
  435. }()
  436. serverStdin, err := session.StdinPipe()
  437. if err != nil {
  438. t.Fatalf("StdinPipe failed: %v", err)
  439. }
  440. written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestBytes)
  441. if err != nil {
  442. t.Fatalf("falied to copy origBuf to serverStdin: %v", err)
  443. }
  444. if written != windowTestBytes {
  445. t.Fatalf("Wrote only %d of %d bytes to server", written, windowTestBytes)
  446. }
  447. echoedBytes := <-result
  448. if !bytes.Equal(origBytes, echoedBytes) {
  449. t.Fatalf("Echoed buffer differed from original, orig %d, echoed %d", len(origBytes), len(echoedBytes))
  450. }
  451. }
  452. type exitStatusMsg struct {
  453. PeersId uint32
  454. Request string
  455. WantReply bool
  456. Status uint32
  457. }
  458. type exitSignalMsg struct {
  459. PeersId uint32
  460. Request string
  461. WantReply bool
  462. Signal string
  463. CoreDumped bool
  464. Errmsg string
  465. Lang string
  466. }
  467. func newServerShell(ch *serverChan, prompt string) *ServerTerminal {
  468. term := terminal.NewTerminal(ch, prompt)
  469. return &ServerTerminal{
  470. Term: term,
  471. Channel: ch,
  472. }
  473. }
  474. func exitStatusZeroHandler(ch *serverChan, t *testing.T) {
  475. defer ch.Close()
  476. // this string is returned to stdout
  477. shell := newServerShell(ch, "> ")
  478. readLine(shell, t)
  479. sendStatus(0, ch, t)
  480. }
  481. func exitStatusNonZeroHandler(ch *serverChan, t *testing.T) {
  482. defer ch.Close()
  483. shell := newServerShell(ch, "> ")
  484. readLine(shell, t)
  485. sendStatus(15, ch, t)
  486. }
  487. func exitSignalAndStatusHandler(ch *serverChan, t *testing.T) {
  488. defer ch.Close()
  489. shell := newServerShell(ch, "> ")
  490. readLine(shell, t)
  491. sendStatus(15, ch, t)
  492. sendSignal("TERM", ch, t)
  493. }
  494. func exitSignalHandler(ch *serverChan, t *testing.T) {
  495. defer ch.Close()
  496. shell := newServerShell(ch, "> ")
  497. readLine(shell, t)
  498. sendSignal("TERM", ch, t)
  499. }
  500. func exitSignalUnknownHandler(ch *serverChan, t *testing.T) {
  501. defer ch.Close()
  502. shell := newServerShell(ch, "> ")
  503. readLine(shell, t)
  504. sendSignal("SYS", ch, t)
  505. }
  506. func exitWithoutSignalOrStatus(ch *serverChan, t *testing.T) {
  507. defer ch.Close()
  508. shell := newServerShell(ch, "> ")
  509. readLine(shell, t)
  510. }
  511. func shellHandler(ch *serverChan, t *testing.T) {
  512. defer ch.Close()
  513. // this string is returned to stdout
  514. shell := newServerShell(ch, "golang")
  515. readLine(shell, t)
  516. sendStatus(0, ch, t)
  517. }
  518. func readLine(shell *ServerTerminal, t *testing.T) {
  519. if _, err := shell.ReadLine(); err != nil && err != io.EOF {
  520. t.Errorf("unable to read line: %v", err)
  521. }
  522. }
  523. func sendStatus(status uint32, ch *serverChan, t *testing.T) {
  524. msg := exitStatusMsg{
  525. PeersId: ch.remoteId,
  526. Request: "exit-status",
  527. WantReply: false,
  528. Status: status,
  529. }
  530. if err := ch.writePacket(marshal(msgChannelRequest, msg)); err != nil {
  531. t.Errorf("unable to send status: %v", err)
  532. }
  533. }
  534. func sendSignal(signal string, ch *serverChan, t *testing.T) {
  535. sig := exitSignalMsg{
  536. PeersId: ch.remoteId,
  537. Request: "exit-signal",
  538. WantReply: false,
  539. Signal: signal,
  540. CoreDumped: false,
  541. Errmsg: "Process terminated",
  542. Lang: "en-GB-oed",
  543. }
  544. if err := ch.writePacket(marshal(msgChannelRequest, sig)); err != nil {
  545. t.Errorf("unable to send signal: %v", err)
  546. }
  547. }
  548. func sendInvalidRecord(ch *serverChan, t *testing.T) {
  549. defer ch.Close()
  550. packet := make([]byte, 1+4+4+1)
  551. packet[0] = msgChannelData
  552. marshalUint32(packet[1:], 29348723 /* invalid channel id */)
  553. marshalUint32(packet[5:], 1)
  554. packet[9] = 42
  555. if err := ch.writePacket(packet); err != nil {
  556. t.Errorf("unable send invalid record: %v", err)
  557. }
  558. }
  559. func sendZeroWindowAdjust(ch *serverChan, t *testing.T) {
  560. defer ch.Close()
  561. // send a bogus zero sized window update
  562. ch.sendWindowAdj(0)
  563. shell := newServerShell(ch, "> ")
  564. readLine(shell, t)
  565. sendStatus(0, ch, t)
  566. }
  567. func discardHandler(ch *serverChan, t *testing.T) {
  568. defer ch.Close()
  569. // grow the window to avoid being fooled by
  570. // the initial 1 << 14 window.
  571. ch.sendWindowAdj(1024 * 1024)
  572. io.Copy(ioutil.Discard, ch)
  573. }
  574. func largeSendHandler(ch *serverChan, t *testing.T) {
  575. defer ch.Close()
  576. // grow the window to avoid being fooled by
  577. // the initial 1 << 14 window.
  578. ch.sendWindowAdj(1024 * 1024)
  579. shell := newServerShell(ch, "> ")
  580. readLine(shell, t)
  581. // try to send more than the 32k window
  582. // will allow
  583. if err := ch.writePacket(make([]byte, 128*1024)); err == nil {
  584. t.Errorf("wrote packet larger than 32k")
  585. }
  586. }
  587. func echoHandler(ch *serverChan, t *testing.T) {
  588. defer ch.Close()
  589. if n, err := copyNRandomly("echohandler", ch, ch, windowTestBytes); err != nil {
  590. t.Errorf("short write, wrote %d, expected %d: %v ", n, windowTestBytes, err)
  591. }
  592. }
  593. // copyNRandomly copies n bytes from src to dst. It uses a variable, and random,
  594. // buffer size to exercise more code paths.
  595. func copyNRandomly(title string, dst io.Writer, src io.Reader, n int) (int, error) {
  596. var (
  597. buf = make([]byte, 32*1024)
  598. written int
  599. remaining = n
  600. )
  601. for remaining > 0 {
  602. l := rand.Intn(1 << 15)
  603. if remaining < l {
  604. l = remaining
  605. }
  606. nr, er := src.Read(buf[:l])
  607. nw, ew := dst.Write(buf[:nr])
  608. remaining -= nw
  609. written += nw
  610. if ew != nil {
  611. return written, ew
  612. }
  613. if nr != nw {
  614. return written, io.ErrShortWrite
  615. }
  616. if er != nil && er != io.EOF {
  617. return written, er
  618. }
  619. }
  620. return written, nil
  621. }