@@ -58,7 +58,7 @@ import (
5858 "github.com/XinFinOrg/XDC-Subnet/p2p/discv5"
5959 "github.com/XinFinOrg/XDC-Subnet/p2p/nat"
6060 "github.com/XinFinOrg/XDC-Subnet/params"
61- "golang.org/x/net /websocket"
61+ "github.com/gorilla /websocket"
6262)
6363
6464var (
@@ -204,14 +204,21 @@ type faucet struct {
204204 nonce uint64 // Current pending nonce of the faucet
205205 price * big.Int // Current gas price to issue funds with
206206
207- conns []* websocket. Conn // Currently live websocket connections
207+ conns []* wsConn // Currently live websocket connections
208208 timeouts map [string ]time.Time // History of users and their funding timeouts
209209 reqs []* request // Currently pending funding requests
210210 update chan struct {} // Channel to signal request updates
211211
212212 lock sync.RWMutex // Lock protecting the faucet's internals
213213}
214214
215+ // wsConn wraps a websocket connection with a write mutex as the underlying
216+ // websocket library does not synchronize access to the stream.
217+ type wsConn struct {
218+ conn * websocket.Conn
219+ wlock sync.Mutex
220+ }
221+
215222func newFaucet (genesis * core.Genesis , port int , enodes []* discv5.Node , network uint64 , stats string , ks * keystore.KeyStore , index []byte ) (* faucet , error ) {
216223 // Assemble the raw devp2p protocol stack
217224 stack , err := node .New (& node.Config {
@@ -289,7 +296,7 @@ func (f *faucet) listenAndServe(port int) error {
289296 go f .loop ()
290297
291298 http .HandleFunc ("/" , f .webHandler )
292- http .Handle ("/api" , websocket . Handler ( f .apiHandler ) )
299+ http .HandleFunc ("/api" , f .apiHandler )
293300
294301 return http .ListenAndServe (fmt .Sprintf (":%d" , port ), nil )
295302}
@@ -301,18 +308,24 @@ func (f *faucet) webHandler(w http.ResponseWriter, r *http.Request) {
301308}
302309
303310// apiHandler handles requests for Ether grants and transaction statuses.
304- func (f * faucet ) apiHandler (conn * websocket.Conn ) {
311+ func (f * faucet ) apiHandler (w http.ResponseWriter , r * http.Request ) {
312+ upgrader := websocket.Upgrader {}
313+ conn , err := upgrader .Upgrade (w , r , nil )
314+ if err != nil {
315+ return
316+ }
305317 // Start tracking the connection and drop at the end
306318 defer conn .Close ()
307319
308320 f .lock .Lock ()
309- f .conns = append (f .conns , conn )
321+ wsconn := & wsConn {conn : conn }
322+ f .conns = append (f .conns , wsconn )
310323 f .lock .Unlock ()
311324
312325 defer func () {
313326 f .lock .Lock ()
314327 for i , c := range f .conns {
315- if c == conn {
328+ if c . conn == conn {
316329 f .conns = append (f .conns [:i ], f .conns [i + 1 :]... )
317330 break
318331 }
@@ -324,7 +337,6 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
324337 head * types.Header
325338 balance * big.Int
326339 nonce uint64
327- err error
328340 )
329341 for {
330342 // Attempt to retrieve the stats, may error on no faucet connectivity
@@ -340,7 +352,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
340352
341353 // If stats retrieval failed, wait a bit and retry
342354 if err != nil {
343- if err = sendError (conn , errors .New ("Faucet offline: " + err .Error ())); err != nil {
355+ if err = sendError (wsconn , errors .New ("Faucet offline: " + err .Error ())); err != nil {
344356 log .Warn ("Failed to send faucet error to client" , "err" , err )
345357 return
346358 }
@@ -351,7 +363,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
351363 break
352364 }
353365 // Send over the initial stats and the latest header
354- if err = send (conn , map [string ]interface {}{
366+ if err = send (wsconn , map [string ]interface {}{
355367 "funds" : balance .Div (balance , ether ),
356368 "funded" : nonce ,
357369 "peers" : f .stack .Server ().PeerCount (),
@@ -360,7 +372,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
360372 log .Warn ("Failed to send initial stats to client" , "err" , err )
361373 return
362374 }
363- if err = send (conn , head , 3 * time .Second ); err != nil {
375+ if err = send (wsconn , head , 3 * time .Second ); err != nil {
364376 log .Warn ("Failed to send initial header to client" , "err" , err )
365377 return
366378 }
@@ -372,19 +384,19 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
372384 Tier uint `json:"tier"`
373385 Captcha string `json:"captcha"`
374386 }
375- if err = websocket . JSON . Receive ( conn , & msg ); err != nil {
387+ if err = conn . ReadJSON ( & msg ); err != nil {
376388 return
377389 }
378390 if ! * noauthFlag && ! strings .HasPrefix (msg .URL , "https://gist.github.com/" ) && ! strings .HasPrefix (msg .URL , "https://twitter.com/" ) &&
379391 ! strings .HasPrefix (msg .URL , "https://plus.google.com/" ) && ! strings .HasPrefix (msg .URL , "https://www.facebook.com/" ) {
380- if err = sendError (conn , errors .New ("URL doesn't link to supported services" )); err != nil {
392+ if err = sendError (wsconn , errors .New ("URL doesn't link to supported services" )); err != nil {
381393 log .Warn ("Failed to send URL error to client" , "err" , err )
382394 return
383395 }
384396 continue
385397 }
386398 if msg .Tier >= uint (* tiersFlag ) {
387- if err = sendError (conn , errors .New ("Invalid funding tier requested" )); err != nil {
399+ if err = sendError (wsconn , errors .New ("Invalid funding tier requested" )); err != nil {
388400 log .Warn ("Failed to send tier error to client" , "err" , err )
389401 return
390402 }
@@ -400,7 +412,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
400412
401413 res , err := http .PostForm ("https://www.google.com/recaptcha/api/siteverify" , form )
402414 if err != nil {
403- if err = sendError (conn , err ); err != nil {
415+ if err = sendError (wsconn , err ); err != nil {
404416 log .Warn ("Failed to send captcha post error to client" , "err" , err )
405417 return
406418 }
@@ -413,15 +425,15 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
413425 err = json .NewDecoder (res .Body ).Decode (& result )
414426 res .Body .Close ()
415427 if err != nil {
416- if err = sendError (conn , err ); err != nil {
428+ if err = sendError (wsconn , err ); err != nil {
417429 log .Warn ("Failed to send captcha decode error to client" , "err" , err )
418430 return
419431 }
420432 continue
421433 }
422434 if ! result .Success {
423435 log .Warn ("Captcha verification failed" , "err" , string (result .Errors ))
424- if err = sendError (conn , errors .New ("Beep-bop, you're a robot!" )); err != nil {
436+ if err = sendError (wsconn , errors .New ("Beep-bop, you're a robot!" )); err != nil {
425437 log .Warn ("Failed to send captcha failure to client" , "err" , err )
426438 return
427439 }
@@ -436,7 +448,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
436448 )
437449 switch {
438450 case strings .HasPrefix (msg .URL , "https://gist.github.com/" ):
439- if err = sendError (conn , errors .New ("GitHub authentication discontinued at the official request of GitHub" )); err != nil {
451+ if err = sendError (wsconn , errors .New ("GitHub authentication discontinued at the official request of GitHub" )); err != nil {
440452 log .Warn ("Failed to send GitHub deprecation to client" , "err" , err )
441453 return
442454 }
@@ -453,7 +465,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
453465 err = errors .New ("Something funky happened, please open an issue at https://github.com/XinFinOrg/XDC-Subnet/issues" )
454466 }
455467 if err != nil {
456- if err = sendError (conn , err ); err != nil {
468+ if err = sendError (wsconn , err ); err != nil {
457469 log .Warn ("Failed to send prefix error to client" , "err" , err )
458470 return
459471 }
@@ -477,7 +489,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
477489 signed , err := f .keystore .SignTx (f .account , tx , f .config .ChainId )
478490 if err != nil {
479491 f .lock .Unlock ()
480- if err = sendError (conn , err ); err != nil {
492+ if err = sendError (wsconn , err ); err != nil {
481493 log .Warn ("Failed to send transaction creation error to client" , "err" , err )
482494 return
483495 }
@@ -486,7 +498,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
486498 // Submit the transaction and mark as funded if successful
487499 if err := f .client .SendTransaction (context .Background (), signed ); err != nil {
488500 f .lock .Unlock ()
489- if err = sendError (conn , err ); err != nil {
501+ if err = sendError (wsconn , err ); err != nil {
490502 log .Warn ("Failed to send transaction transmission error to client" , "err" , err )
491503 return
492504 }
@@ -505,13 +517,13 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
505517
506518 // Send an error if too frequent funding, othewise a success
507519 if ! fund {
508- if err = sendError (conn , fmt .Errorf ("%s left until next allowance" , common .PrettyDuration (timeout .Sub (time .Now ())))); err != nil { // nolint: gosimple
520+ if err = sendError (wsconn , fmt .Errorf ("%s left until next allowance" , common .PrettyDuration (timeout .Sub (time .Now ())))); err != nil { // nolint: gosimple
509521 log .Warn ("Failed to send funding error to client" , "err" , err )
510522 return
511523 }
512524 continue
513525 }
514- if err = sendSuccess (conn , fmt .Sprintf ("Funding request accepted for %s into %s" , username , address .Hex ())); err != nil {
526+ if err = sendSuccess (wsconn , fmt .Sprintf ("Funding request accepted for %s into %s" , username , address .Hex ())); err != nil {
515527 log .Warn ("Failed to send funding success to client" , "err" , err )
516528 return
517529 }
@@ -581,12 +593,12 @@ func (f *faucet) loop() {
581593 "requests" : f .reqs ,
582594 }, time .Second ); err != nil {
583595 log .Warn ("Failed to send stats to client" , "err" , err )
584- conn .Close ()
596+ conn .conn . Close ()
585597 continue
586598 }
587599 if err := send (conn , head , time .Second ); err != nil {
588600 log .Warn ("Failed to send header to client" , "err" , err )
589- conn .Close ()
601+ conn .conn . Close ()
590602 }
591603 }
592604 f .lock .RUnlock ()
@@ -608,7 +620,7 @@ func (f *faucet) loop() {
608620 for _ , conn := range f .conns {
609621 if err := send (conn , map [string ]interface {}{"requests" : f .reqs }, time .Second ); err != nil {
610622 log .Warn ("Failed to send requests to client" , "err" , err )
611- conn .Close ()
623+ conn .conn . Close ()
612624 }
613625 }
614626 f .lock .RUnlock ()
@@ -618,23 +630,25 @@ func (f *faucet) loop() {
618630
619631// sends transmits a data packet to the remote end of the websocket, but also
620632// setting a write deadline to prevent waiting forever on the node.
621- func send (conn * websocket. Conn , value interface {}, timeout time.Duration ) error {
633+ func send (conn * wsConn , value interface {}, timeout time.Duration ) error {
622634 if timeout == 0 {
623635 timeout = 60 * time .Second
624636 }
625- conn .SetWriteDeadline (time .Now ().Add (timeout ))
626- return websocket .JSON .Send (conn , value )
637+ conn .wlock .Lock ()
638+ defer conn .wlock .Unlock ()
639+ conn .conn .SetWriteDeadline (time .Now ().Add (timeout ))
640+ return conn .conn .WriteJSON (value )
627641}
628642
629643// sendError transmits an error to the remote end of the websocket, also setting
630644// the write deadline to 1 second to prevent waiting forever.
631- func sendError (conn * websocket. Conn , err error ) error {
645+ func sendError (conn * wsConn , err error ) error {
632646 return send (conn , map [string ]string {"error" : err .Error ()}, time .Second )
633647}
634648
635649// sendSuccess transmits a success message to the remote end of the websocket, also
636650// setting the write deadline to 1 second to prevent waiting forever.
637- func sendSuccess (conn * websocket. Conn , msg string ) error {
651+ func sendSuccess (conn * wsConn , msg string ) error {
638652 return send (conn , map [string ]string {"success" : msg }, time .Second )
639653}
640654
0 commit comments