server.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. package server
  2. import (
  3. "crypto/tls"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net"
  8. "net/http"
  9. "os"
  10. "strings"
  11. "github.com/Sirupsen/logrus"
  12. "github.com/docker/distribution/registry/api/errcode"
  13. "github.com/docker/docker/api"
  14. "github.com/docker/docker/daemon"
  15. "github.com/docker/docker/pkg/sockets"
  16. "github.com/docker/docker/utils"
  17. "github.com/gorilla/mux"
  18. "golang.org/x/net/context"
  19. )
  20. // Config provides the configuration for the API server
  21. type Config struct {
  22. Logging bool
  23. EnableCors bool
  24. CorsHeaders string
  25. Version string
  26. SocketGroup string
  27. TLSConfig *tls.Config
  28. }
  29. // Server contains instance details for the server
  30. type Server struct {
  31. daemon *daemon.Daemon
  32. cfg *Config
  33. router *mux.Router
  34. start chan struct{}
  35. servers []serverCloser
  36. }
  37. // New returns a new instance of the server based on the specified configuration.
  38. func New(cfg *Config) *Server {
  39. srv := &Server{
  40. cfg: cfg,
  41. start: make(chan struct{}),
  42. }
  43. srv.router = createRouter(srv)
  44. return srv
  45. }
  46. // Close closes servers and thus stop receiving requests
  47. func (s *Server) Close() {
  48. for _, srv := range s.servers {
  49. if err := srv.Close(); err != nil {
  50. logrus.Error(err)
  51. }
  52. }
  53. }
  54. type serverCloser interface {
  55. Serve() error
  56. Close() error
  57. }
  58. // ServeAPI loops through all of the protocols sent in to docker and spawns
  59. // off a go routine to setup a serving http.Server for each.
  60. func (s *Server) ServeAPI(protoAddrs []string) error {
  61. var chErrors = make(chan error, len(protoAddrs))
  62. for _, protoAddr := range protoAddrs {
  63. protoAddrParts := strings.SplitN(protoAddr, "://", 2)
  64. if len(protoAddrParts) != 2 {
  65. return fmt.Errorf("bad format, expected PROTO://ADDR")
  66. }
  67. srv, err := s.newServer(protoAddrParts[0], protoAddrParts[1])
  68. if err != nil {
  69. return err
  70. }
  71. s.servers = append(s.servers, srv...)
  72. for _, s := range srv {
  73. logrus.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
  74. go func(s serverCloser) {
  75. if err := s.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
  76. err = nil
  77. }
  78. chErrors <- err
  79. }(s)
  80. }
  81. }
  82. for i := 0; i < len(protoAddrs); i++ {
  83. err := <-chErrors
  84. if err != nil {
  85. return err
  86. }
  87. }
  88. return nil
  89. }
  90. // HTTPServer contains an instance of http server and the listener.
  91. // srv *http.Server, contains configuration to create a http server and a mux router with all api end points.
  92. // l net.Listener, is a TCP or Socket listener that dispatches incoming request to the router.
  93. type HTTPServer struct {
  94. srv *http.Server
  95. l net.Listener
  96. }
  97. // Serve starts listening for inbound requests.
  98. func (s *HTTPServer) Serve() error {
  99. return s.srv.Serve(s.l)
  100. }
  101. // Close closes the HTTPServer from listening for the inbound requests.
  102. func (s *HTTPServer) Close() error {
  103. return s.l.Close()
  104. }
  105. // HTTPAPIFunc is an adapter to allow the use of ordinary functions as Docker API endpoints.
  106. // Any function that has the appropriate signature can be register as a API endpoint (e.g. getVersion).
  107. type HTTPAPIFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
  108. func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
  109. conn, _, err := w.(http.Hijacker).Hijack()
  110. if err != nil {
  111. return nil, nil, err
  112. }
  113. // Flush the options to make sure the client sets the raw mode
  114. conn.Write([]byte{})
  115. return conn, conn, nil
  116. }
  117. func closeStreams(streams ...interface{}) {
  118. for _, stream := range streams {
  119. if tcpc, ok := stream.(interface {
  120. CloseWrite() error
  121. }); ok {
  122. tcpc.CloseWrite()
  123. } else if closer, ok := stream.(io.Closer); ok {
  124. closer.Close()
  125. }
  126. }
  127. }
  128. // checkForJSON makes sure that the request's Content-Type is application/json.
  129. func checkForJSON(r *http.Request) error {
  130. ct := r.Header.Get("Content-Type")
  131. // No Content-Type header is ok as long as there's no Body
  132. if ct == "" {
  133. if r.Body == nil || r.ContentLength == 0 {
  134. return nil
  135. }
  136. }
  137. // Otherwise it better be json
  138. if api.MatchesContentType(ct, "application/json") {
  139. return nil
  140. }
  141. return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
  142. }
  143. //If we don't do this, POST method without Content-type (even with empty body) will fail
  144. func parseForm(r *http.Request) error {
  145. if r == nil {
  146. return nil
  147. }
  148. if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
  149. return err
  150. }
  151. return nil
  152. }
  153. func parseMultipartForm(r *http.Request) error {
  154. if err := r.ParseMultipartForm(4096); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
  155. return err
  156. }
  157. return nil
  158. }
  159. func httpError(w http.ResponseWriter, err error) {
  160. if err == nil || w == nil {
  161. logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
  162. return
  163. }
  164. statusCode := http.StatusInternalServerError
  165. errMsg := err.Error()
  166. // Based on the type of error we get we need to process things
  167. // slightly differently to extract the error message.
  168. // In the 'errcode.*' cases there are two different type of
  169. // error that could be returned. errocode.ErrorCode is the base
  170. // type of error object - it is just an 'int' that can then be
  171. // used as the look-up key to find the message. errorcode.Error
  172. // extends errorcode.Error by adding error-instance specific
  173. // data, like 'details' or variable strings to be inserted into
  174. // the message.
  175. //
  176. // Ideally, we should just be able to call err.Error() for all
  177. // cases but the errcode package doesn't support that yet.
  178. //
  179. // Additionally, in both errcode cases, there might be an http
  180. // status code associated with it, and if so use it.
  181. switch err.(type) {
  182. case errcode.ErrorCode:
  183. daError, _ := err.(errcode.ErrorCode)
  184. statusCode = daError.Descriptor().HTTPStatusCode
  185. errMsg = daError.Message()
  186. case errcode.Error:
  187. // For reference, if you're looking for a particular error
  188. // then you can do something like :
  189. // import ( derr "github.com/docker/docker/errors" )
  190. // if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }
  191. daError, _ := err.(errcode.Error)
  192. statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
  193. errMsg = daError.Message
  194. default:
  195. // This part of will be removed once we've
  196. // converted everything over to use the errcode package
  197. // FIXME: this is brittle and should not be necessary.
  198. // If we need to differentiate between different possible error types,
  199. // we should create appropriate error types with clearly defined meaning
  200. errStr := strings.ToLower(err.Error())
  201. for keyword, status := range map[string]int{
  202. "not found": http.StatusNotFound,
  203. "no such": http.StatusNotFound,
  204. "bad parameter": http.StatusBadRequest,
  205. "conflict": http.StatusConflict,
  206. "impossible": http.StatusNotAcceptable,
  207. "wrong login/password": http.StatusUnauthorized,
  208. "hasn't been activated": http.StatusForbidden,
  209. } {
  210. if strings.Contains(errStr, keyword) {
  211. statusCode = status
  212. break
  213. }
  214. }
  215. }
  216. if statusCode == 0 {
  217. statusCode = http.StatusInternalServerError
  218. }
  219. logrus.WithFields(logrus.Fields{"statusCode": statusCode, "err": utils.GetErrorMessage(err)}).Error("HTTP Error")
  220. http.Error(w, errMsg, statusCode)
  221. }
  222. // writeJSON writes the value v to the http response stream as json with standard
  223. // json encoding.
  224. func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
  225. w.Header().Set("Content-Type", "application/json")
  226. w.WriteHeader(code)
  227. return json.NewEncoder(w).Encode(v)
  228. }
  229. func (s *Server) optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  230. w.WriteHeader(http.StatusOK)
  231. return nil
  232. }
  233. func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) {
  234. logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
  235. w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
  236. w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
  237. w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
  238. }
  239. func (s *Server) ping(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  240. _, err := w.Write([]byte{'O', 'K'})
  241. return err
  242. }
  243. func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) {
  244. if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert {
  245. logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
  246. }
  247. if l, err = sockets.NewTCPSocket(addr, s.cfg.TLSConfig, s.start); err != nil {
  248. return nil, err
  249. }
  250. if err := allocateDaemonPort(addr); err != nil {
  251. return nil, err
  252. }
  253. return
  254. }
  255. func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHandler HTTPAPIFunc) http.HandlerFunc {
  256. return func(w http.ResponseWriter, r *http.Request) {
  257. // log the handler generation
  258. logrus.Debugf("Calling %s %s", localMethod, localRoute)
  259. // Define the context that we'll pass around to share info
  260. // like the docker-request-id.
  261. //
  262. // The 'context' will be used for global data that should
  263. // apply to all requests. Data that is specific to the
  264. // immediate function being called should still be passed
  265. // as 'args' on the function call.
  266. ctx := context.Background()
  267. handlerFunc := s.handleWithGlobalMiddlewares(localHandler)
  268. if err := handlerFunc(ctx, w, r, mux.Vars(r)); err != nil {
  269. logrus.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, utils.GetErrorMessage(err))
  270. httpError(w, err)
  271. }
  272. }
  273. }
  274. // createRouter initializes the main router the server uses.
  275. // we keep enableCors just for legacy usage, need to be removed in the future
  276. func createRouter(s *Server) *mux.Router {
  277. r := mux.NewRouter()
  278. if os.Getenv("DEBUG") != "" {
  279. profilerSetup(r, "/debug/")
  280. }
  281. m := map[string]map[string]HTTPAPIFunc{
  282. "HEAD": {
  283. "/containers/{name:.*}/archive": s.headContainersArchive,
  284. },
  285. "GET": {
  286. "/_ping": s.ping,
  287. "/events": s.getEvents,
  288. "/info": s.getInfo,
  289. "/version": s.getVersion,
  290. "/images/json": s.getImagesJSON,
  291. "/images/search": s.getImagesSearch,
  292. "/images/get": s.getImagesGet,
  293. "/images/{name:.*}/get": s.getImagesGet,
  294. "/images/{name:.*}/history": s.getImagesHistory,
  295. "/images/{name:.*}/json": s.getImagesByName,
  296. "/containers/json": s.getContainersJSON,
  297. "/containers/{name:.*}/export": s.getContainersExport,
  298. "/containers/{name:.*}/changes": s.getContainersChanges,
  299. "/containers/{name:.*}/json": s.getContainersByName,
  300. "/containers/{name:.*}/top": s.getContainersTop,
  301. "/containers/{name:.*}/logs": s.getContainersLogs,
  302. "/containers/{name:.*}/stats": s.getContainersStats,
  303. "/containers/{name:.*}/attach/ws": s.wsContainersAttach,
  304. "/exec/{id:.*}/json": s.getExecByID,
  305. "/containers/{name:.*}/archive": s.getContainersArchive,
  306. "/volumes": s.getVolumesList,
  307. "/volumes/{name:.*}": s.getVolumeByName,
  308. },
  309. "POST": {
  310. "/auth": s.postAuth,
  311. "/commit": s.postCommit,
  312. "/build": s.postBuild,
  313. "/images/create": s.postImagesCreate,
  314. "/images/load": s.postImagesLoad,
  315. "/images/{name:.*}/push": s.postImagesPush,
  316. "/images/{name:.*}/tag": s.postImagesTag,
  317. "/containers/create": s.postContainersCreate,
  318. "/containers/{name:.*}/kill": s.postContainersKill,
  319. "/containers/{name:.*}/pause": s.postContainersPause,
  320. "/containers/{name:.*}/unpause": s.postContainersUnpause,
  321. "/containers/{name:.*}/restart": s.postContainersRestart,
  322. "/containers/{name:.*}/start": s.postContainersStart,
  323. "/containers/{name:.*}/stop": s.postContainersStop,
  324. "/containers/{name:.*}/wait": s.postContainersWait,
  325. "/containers/{name:.*}/resize": s.postContainersResize,
  326. "/containers/{name:.*}/attach": s.postContainersAttach,
  327. "/containers/{name:.*}/copy": s.postContainersCopy,
  328. "/containers/{name:.*}/exec": s.postContainerExecCreate,
  329. "/exec/{name:.*}/start": s.postContainerExecStart,
  330. "/exec/{name:.*}/resize": s.postContainerExecResize,
  331. "/containers/{name:.*}/rename": s.postContainerRename,
  332. "/volumes": s.postVolumesCreate,
  333. },
  334. "PUT": {
  335. "/containers/{name:.*}/archive": s.putContainersArchive,
  336. },
  337. "DELETE": {
  338. "/containers/{name:.*}": s.deleteContainers,
  339. "/images/{name:.*}": s.deleteImages,
  340. "/volumes/{name:.*}": s.deleteVolumes,
  341. },
  342. "OPTIONS": {
  343. "": s.optionsHandler,
  344. },
  345. }
  346. for method, routes := range m {
  347. for route, fct := range routes {
  348. logrus.Debugf("Registering %s, %s", method, route)
  349. // NOTE: scope issue, make sure the variables are local and won't be changed
  350. localRoute := route
  351. localFct := fct
  352. localMethod := method
  353. // build the handler function
  354. f := s.makeHTTPHandler(localMethod, localRoute, localFct)
  355. // add the new route
  356. if localRoute == "" {
  357. r.Methods(localMethod).HandlerFunc(f)
  358. } else {
  359. r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
  360. r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
  361. }
  362. }
  363. }
  364. return r
  365. }