github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/corehttp/corehttp.go (about) 1 /* 2 Package corehttp provides utilities for the webui, gateways, and other 3 high-level HTTP interfaces to IPFS. 4 */ 5 package corehttp 6 7 import ( 8 "fmt" 9 "net" 10 "net/http" 11 "time" 12 13 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 14 manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" 15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" 16 core "github.com/ipfs/go-ipfs/core" 17 eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog" 18 ) 19 20 var log = eventlog.Logger("core/server") 21 22 // ServeOption registers any HTTP handlers it provides on the given mux. 23 // It returns the mux to expose to future options, which may be a new mux if it 24 // is interested in mediating requests to future options, or the same mux 25 // initially passed in if not. 26 type ServeOption func(*core.IpfsNode, net.Listener, *http.ServeMux) (*http.ServeMux, error) 27 28 // makeHandler turns a list of ServeOptions into a http.Handler that implements 29 // all of the given options, in order. 30 func makeHandler(n *core.IpfsNode, l net.Listener, options ...ServeOption) (http.Handler, error) { 31 topMux := http.NewServeMux() 32 mux := topMux 33 for _, option := range options { 34 var err error 35 mux, err = option(n, l, mux) 36 if err != nil { 37 return nil, err 38 } 39 } 40 return topMux, nil 41 } 42 43 // ListenAndServe runs an HTTP server listening at |listeningMultiAddr| with 44 // the given serve options. The address must be provided in multiaddr format. 45 // 46 // TODO intelligently parse address strings in other formats so long as they 47 // unambiguously map to a valid multiaddr. e.g. for convenience, ":8080" should 48 // map to "/ip4/0.0.0.0/tcp/8080". 49 func ListenAndServe(n *core.IpfsNode, listeningMultiAddr string, options ...ServeOption) error { 50 addr, err := ma.NewMultiaddr(listeningMultiAddr) 51 if err != nil { 52 return err 53 } 54 55 list, err := manet.Listen(addr) 56 if err != nil { 57 return err 58 } 59 60 // we might have listened to /tcp/0 - lets see what we are listing on 61 addr = list.Multiaddr() 62 fmt.Printf("API server listening on %s\n", addr) 63 64 return Serve(n, list.NetListener(), options...) 65 } 66 67 func Serve(node *core.IpfsNode, lis net.Listener, options ...ServeOption) error { 68 handler, err := makeHandler(node, lis, options...) 69 if err != nil { 70 return err 71 } 72 73 addr, err := manet.FromNetAddr(lis.Addr()) 74 if err != nil { 75 return err 76 } 77 78 // if the server exits beforehand 79 var serverError error 80 serverExited := make(chan struct{}) 81 82 node.Process().Go(func(p goprocess.Process) { 83 serverError = http.Serve(lis, handler) 84 close(serverExited) 85 }) 86 87 // wait for server to exit. 88 select { 89 case <-serverExited: 90 91 // if node being closed before server exits, close server 92 case <-node.Process().Closing(): 93 log.Infof("server at %s terminating...", addr) 94 95 lis.Close() 96 97 outer: 98 for { 99 // wait until server exits 100 select { 101 case <-serverExited: 102 // if the server exited as we are closing, we really dont care about errors 103 serverError = nil 104 break outer 105 case <-time.After(5 * time.Second): 106 log.Infof("waiting for server at %s to terminate...", addr) 107 } 108 } 109 } 110 111 log.Infof("server at %s terminated", addr) 112 return serverError 113 }