Browse code

Refactor api.go to use a factory with named functions

Guillaume J. Charmes authored on 2013/05/08 08:33:12
Showing 3 changed files
... ...
@@ -40,86 +40,118 @@ func httpError(w http.ResponseWriter, err error) {
40 40
 	}
41 41
 }
42 42
 
43
-func ListenAndServe(addr string, srv *Server) error {
44
-	r := mux.NewRouter()
45
-	log.Printf("Listening for HTTP on %s\n", addr)
43
+func getAuth(srv *Server, w http.ResponseWriter, r *http.Request) error {
44
+	log.Println(r.Method, r.RequestURI)
45
+	var out auth.AuthConfig
46
+	out.Username = srv.runtime.authConfig.Username
47
+	out.Email = srv.runtime.authConfig.Email
48
+	b, err := json.Marshal(out)
49
+	if err != nil {
50
+		http.Error(w, err.Error(), http.StatusInternalServerError)
51
+		return err
52
+	} else {
53
+		w.Header().Set("Content-Type", "application/json")
54
+		w.Write(b)
55
+	}
56
+	return nil
57
+}
58
+
59
+func postAuth(srv *Server, w http.ResponseWriter, r *http.Request) error {
60
+	log.Println(r.Method, r.RequestURI)
61
+	var config auth.AuthConfig
62
+	if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
63
+		http.Error(w, err.Error(), http.StatusInternalServerError)
64
+		return err
65
+	}
46 66
 
47
-	r.Path("/auth").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
48
-		log.Println(r.Method, r.RequestURI)
49
-		var out auth.AuthConfig
50
-		out.Username = srv.runtime.authConfig.Username
51
-		out.Email = srv.runtime.authConfig.Email
52
-		b, err := json.Marshal(out)
67
+	if config.Username == srv.runtime.authConfig.Username {
68
+		config.Password = srv.runtime.authConfig.Password
69
+	}
70
+
71
+	newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root)
72
+	status, err := auth.Login(newAuthConfig)
73
+	if err != nil {
74
+		http.Error(w, err.Error(), http.StatusInternalServerError)
75
+		return err
76
+	} else {
77
+		srv.runtime.graph.getHttpClient().Jar = cookiejar.NewCookieJar()
78
+		srv.runtime.authConfig = newAuthConfig
79
+	}
80
+	if status != "" {
81
+		b, err := json.Marshal(ApiAuth{status})
53 82
 		if err != nil {
54 83
 			http.Error(w, err.Error(), http.StatusInternalServerError)
84
+			return err
55 85
 		} else {
56 86
 			w.Header().Set("Content-Type", "application/json")
57 87
 			w.Write(b)
58 88
 		}
59
-	})
60
-
61
-	r.Path("/auth").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
62
-		log.Println(r.Method, r.RequestURI)
63
-		var config auth.AuthConfig
64
-		if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
65
-			http.Error(w, err.Error(), http.StatusInternalServerError)
66
-			return
67
-		}
89
+	} else {
90
+		w.WriteHeader(http.StatusOK)
91
+	}
92
+	return nil
93
+}
68 94
 
69
-		if config.Username == srv.runtime.authConfig.Username {
70
-			config.Password = srv.runtime.authConfig.Password
71
-		}
95
+func getVersion(srv *Server, w http.ResponseWriter, r *http.Request) error {
96
+	log.Println(r.Method, r.RequestURI)
97
+	m := srv.DockerVersion()
98
+	b, err := json.Marshal(m)
99
+	if err != nil {
100
+		http.Error(w, err.Error(), http.StatusInternalServerError)
101
+		return err
102
+	} else {
103
+		w.Header().Set("Content-Type", "application/json")
104
+		w.Write(b)
105
+	}
106
+	return nil
107
+}
72 108
 
73
-		newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root)
74
-		status, err := auth.Login(newAuthConfig)
75
-		if err != nil {
76
-			http.Error(w, err.Error(), http.StatusInternalServerError)
77
-			return
78
-		} else {
79
-			srv.runtime.graph.getHttpClient().Jar = cookiejar.NewCookieJar()
80
-			srv.runtime.authConfig = newAuthConfig
81
-		}
82
-		if status != "" {
83
-			b, err := json.Marshal(ApiAuth{status})
84
-			if err != nil {
85
-				http.Error(w, err.Error(), http.StatusInternalServerError)
86
-			} else {
87
-				w.Header().Set("Content-Type", "application/json")
88
-				w.Write(b)
89
-			}
90
-		} else {
91
-			w.WriteHeader(http.StatusOK)
92
-		}
93
-	})
109
+func postContainersKill(srv *Server, w http.ResponseWriter, r *http.Request) error {
110
+	log.Println(r.Method, r.RequestURI)
111
+	vars := mux.Vars(r)
112
+	name := vars["name"]
113
+	if err := srv.ContainerKill(name); err != nil {
114
+		httpError(w, err)
115
+		return err
116
+	} else {
117
+		w.WriteHeader(http.StatusOK)
118
+	}
119
+	return nil
120
+}
94 121
 
95
-	r.Path("/version").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
96
-		log.Println(r.Method, r.RequestURI)
97
-		m := srv.DockerVersion()
98
-		b, err := json.Marshal(m)
99
-		if err != nil {
100
-			http.Error(w, err.Error(), http.StatusInternalServerError)
101
-		} else {
102
-			w.Header().Set("Content-Type", "application/json")
103
-			w.Write(b)
104
-		}
105
-	})
122
+func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request) error {
123
+	log.Println(r.Method, r.RequestURI)
124
+	vars := mux.Vars(r)
125
+	name := vars["name"]
106 126
 
107
-	r.Path("/containers/{name:.*}/kill").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
108
-		log.Println(r.Method, r.RequestURI)
109
-		vars := mux.Vars(r)
110
-		name := vars["name"]
111
-		if err := srv.ContainerKill(name); err != nil {
112
-			httpError(w, err)
113
-		} else {
114
-			w.WriteHeader(http.StatusOK)
115
-		}
116
-	})
127
+	file, rwc, err := hijackServer(w)
128
+	if file != nil {
129
+		defer file.Close()
130
+	}
131
+	if rwc != nil {
132
+		defer rwc.Close()
133
+	}
134
+	if err != nil {
135
+		httpError(w, err)
136
+		return err
137
+	}
138
+	fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
139
+	if err := srv.ContainerExport(name, file); err != nil {
140
+		fmt.Fprintf(file, "Error: %s\n", err)
141
+		return err
142
+	}
143
+	return nil
144
+}
117 145
 
118
-	r.Path("/containers/{name:.*}/export").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
119
-		log.Println(r.Method, r.RequestURI)
120
-		vars := mux.Vars(r)
121
-		name := vars["name"]
146
+func getImages(srv *Server, w http.ResponseWriter, r *http.Request) error {
147
+	log.Println(r.Method, r.RequestURI)
148
+	if err := r.ParseForm(); err != nil {
149
+		http.Error(w, err.Error(), http.StatusInternalServerError)
150
+		return err
151
+	}
122 152
 
153
+	viz := r.Form.Get("viz")
154
+	if viz == "1" {
123 155
 		file, rwc, err := hijackServer(w)
124 156
 		if file != nil {
125 157
 			defer file.Close()
... ...
@@ -129,537 +161,615 @@ func ListenAndServe(addr string, srv *Server) error {
129 129
 		}
130 130
 		if err != nil {
131 131
 			httpError(w, err)
132
-			return
132
+			return err
133 133
 		}
134 134
 		fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
135
-		if err := srv.ContainerExport(name, file); err != nil {
136
-			fmt.Fprintln(file, "Error: "+err.Error())
135
+		if err := srv.ImagesViz(file); err != nil {
136
+			fmt.Fprintf(file, "Error: %s\n", err)
137 137
 		}
138
-	})
138
+		return nil
139
+	}
139 140
 
140
-	r.Path("/images").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
141
-		log.Println(r.Method, r.RequestURI)
142
-		if err := r.ParseForm(); err != nil {
143
-			http.Error(w, err.Error(), http.StatusInternalServerError)
144
-			return
145
-		}
141
+	all := r.Form.Get("all")
142
+	filter := r.Form.Get("filter")
143
+	quiet := r.Form.Get("quiet")
146 144
 
147
-		viz := r.Form.Get("viz")
148
-		if viz == "1" {
149
-			file, rwc, err := hijackServer(w)
150
-			if file != nil {
151
-				defer file.Close()
152
-			}
153
-			if rwc != nil {
154
-				defer rwc.Close()
155
-			}
156
-			if err != nil {
157
-				httpError(w, err)
158
-				return
159
-			}
160
-			fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
161
-			if err := srv.ImagesViz(file); err != nil {
162
-				fmt.Fprintln(file, "Error: "+err.Error())
163
-			}
164
-			return
165
-		}
145
+	outs, err := srv.Images(all, filter, quiet)
146
+	if err != nil {
147
+		httpError(w, err)
148
+		return err
149
+	}
150
+	b, err := json.Marshal(outs)
151
+	if err != nil {
152
+		http.Error(w, err.Error(), http.StatusInternalServerError)
153
+		return err
154
+	} else {
155
+		w.Header().Set("Content-Type", "application/json")
156
+		w.Write(b)
157
+	}
158
+	return nil
159
+}
166 160
 
167
-		all := r.Form.Get("all")
168
-		filter := r.Form.Get("filter")
169
-		quiet := r.Form.Get("quiet")
161
+func getInfo(srv *Server, w http.ResponseWriter, r *http.Request) error {
162
+	log.Println(r.Method, r.RequestURI)
163
+	out := srv.DockerInfo()
164
+	b, err := json.Marshal(out)
165
+	if err != nil {
166
+		http.Error(w, err.Error(), http.StatusInternalServerError)
167
+		return err
168
+	} else {
169
+		w.Header().Set("Content-Type", "application/json")
170
+		w.Write(b)
171
+	}
172
+	return nil
173
+}
170 174
 
171
-		outs, err := srv.Images(all, filter, quiet)
172
-		if err != nil {
173
-			httpError(w, err)
174
-			return
175
-		}
176
-		b, err := json.Marshal(outs)
177
-		if err != nil {
178
-			http.Error(w, err.Error(), http.StatusInternalServerError)
179
-		} else {
180
-			w.Header().Set("Content-Type", "application/json")
181
-			w.Write(b)
182
-		}
183
-	})
175
+func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request) error {
176
+	log.Println(r.Method, r.RequestURI)
177
+	vars := mux.Vars(r)
178
+	name := vars["name"]
179
+	outs, err := srv.ImageHistory(name)
180
+	if err != nil {
181
+		httpError(w, err)
182
+		return err
183
+	}
184
+	b, err := json.Marshal(outs)
185
+	if err != nil {
186
+		http.Error(w, err.Error(), http.StatusInternalServerError)
187
+		return err
188
+	} else {
189
+		w.Header().Set("Content-Type", "application/json")
190
+		w.Write(b)
191
+	}
192
+	return nil
193
+}
184 194
 
185
-	r.Path("/info").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
186
-		log.Println(r.Method, r.RequestURI)
187
-		out := srv.DockerInfo()
188
-		b, err := json.Marshal(out)
189
-		if err != nil {
190
-			http.Error(w, err.Error(), http.StatusInternalServerError)
191
-		} else {
192
-			w.Header().Set("Content-Type", "application/json")
193
-			w.Write(b)
194
-		}
195
-	})
195
+func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request) error {
196
+	log.Println(r.Method, r.RequestURI)
197
+	vars := mux.Vars(r)
198
+	name := vars["name"]
199
+	changesStr, err := srv.ContainerChanges(name)
200
+	if err != nil {
201
+		httpError(w, err)
202
+		return err
203
+	}
204
+	b, err := json.Marshal(changesStr)
205
+	if err != nil {
206
+		http.Error(w, err.Error(), http.StatusInternalServerError)
207
+		return err
208
+	} else {
209
+		w.Header().Set("Content-Type", "application/json")
210
+		w.Write(b)
211
+	}
212
+	return nil
213
+}
196 214
 
197
-	r.Path("/images/{name:.*}/history").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
198
-		log.Println(r.Method, r.RequestURI)
199
-		vars := mux.Vars(r)
200
-		name := vars["name"]
201
-		outs, err := srv.ImageHistory(name)
202
-		if err != nil {
203
-			httpError(w, err)
204
-			return
205
-		}
206
-		b, err := json.Marshal(outs)
207
-		if err != nil {
208
-			http.Error(w, err.Error(), http.StatusInternalServerError)
209
-		} else {
210
-			w.Header().Set("Content-Type", "application/json")
211
-			w.Write(b)
212
-		}
213
-	})
215
+func getContainersPort(srv *Server, w http.ResponseWriter, r *http.Request) error {
216
+	log.Println(r.Method, r.RequestURI)
217
+	if err := r.ParseForm(); err != nil {
218
+		http.Error(w, err.Error(), http.StatusInternalServerError)
219
+		return err
220
+	}
221
+	vars := mux.Vars(r)
222
+	name := vars["name"]
223
+	out, err := srv.ContainerPort(name, r.Form.Get("port"))
224
+	if err != nil {
225
+		httpError(w, err)
226
+		return err
227
+	}
228
+	b, err := json.Marshal(ApiPort{out})
229
+	if err != nil {
230
+		http.Error(w, err.Error(), http.StatusInternalServerError)
231
+		return err
232
+	} else {
233
+		w.Header().Set("Content-Type", "application/json")
234
+		w.Write(b)
235
+	}
236
+	return nil
237
+}
214 238
 
215
-	r.Path("/containers/{name:.*}/changes").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
216
-		log.Println(r.Method, r.RequestURI)
217
-		vars := mux.Vars(r)
218
-		name := vars["name"]
219
-		changesStr, err := srv.ContainerChanges(name)
220
-		if err != nil {
221
-			httpError(w, err)
222
-			return
223
-		}
224
-		b, err := json.Marshal(changesStr)
225
-		if err != nil {
226
-			http.Error(w, err.Error(), http.StatusInternalServerError)
227
-		} else {
228
-			w.Header().Set("Content-Type", "application/json")
229
-			w.Write(b)
230
-		}
231
-	})
239
+func getContainers(srv *Server, w http.ResponseWriter, r *http.Request) error {
240
+	log.Println(r.Method, r.RequestURI)
241
+	if err := r.ParseForm(); err != nil {
242
+		http.Error(w, err.Error(), http.StatusInternalServerError)
243
+		return err
244
+	}
245
+	all := r.Form.Get("all")
246
+	notrunc := r.Form.Get("notrunc")
247
+	quiet := r.Form.Get("quiet")
248
+	n, err := strconv.Atoi(r.Form.Get("n"))
249
+	if err != nil {
250
+		n = -1
251
+	}
232 252
 
233
-	r.Path("/containers/{name:.*}/port").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
234
-		log.Println(r.Method, r.RequestURI)
235
-		if err := r.ParseForm(); err != nil {
236
-			http.Error(w, err.Error(), http.StatusInternalServerError)
237
-			return
238
-		}
239
-		vars := mux.Vars(r)
240
-		name := vars["name"]
241
-		out, err := srv.ContainerPort(name, r.Form.Get("port"))
242
-		if err != nil {
243
-			httpError(w, err)
244
-			return
245
-		}
246
-		b, err := json.Marshal(ApiPort{out})
247
-		if err != nil {
248
-			http.Error(w, err.Error(), http.StatusInternalServerError)
249
-		} else {
250
-			w.Header().Set("Content-Type", "application/json")
251
-			w.Write(b)
252
-		}
253
+	outs := srv.Containers(all, notrunc, quiet, n)
254
+	b, err := json.Marshal(outs)
255
+	if err != nil {
256
+		http.Error(w, err.Error(), http.StatusInternalServerError)
257
+		return err
258
+	} else {
259
+		w.Header().Set("Content-Type", "application/json")
260
+		w.Write(b)
261
+	}
262
+	return nil
263
+}
253 264
 
254
-	})
265
+func postImagesTag(srv *Server, w http.ResponseWriter, r *http.Request) error {
266
+	log.Println(r.Method, r.RequestURI)
267
+	if err := r.ParseForm(); err != nil {
268
+		http.Error(w, err.Error(), http.StatusInternalServerError)
269
+		return err
270
+	}
271
+	repo := r.Form.Get("repo")
272
+	tag := r.Form.Get("tag")
273
+	vars := mux.Vars(r)
274
+	name := vars["name"]
275
+	var force bool
276
+	if r.Form.Get("force") == "1" {
277
+		force = true
278
+	}
255 279
 
256
-	r.Path("/containers").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
257
-		log.Println(r.Method, r.RequestURI)
258
-		if err := r.ParseForm(); err != nil {
259
-			http.Error(w, err.Error(), http.StatusInternalServerError)
260
-			return
261
-		}
262
-		all := r.Form.Get("all")
263
-		notrunc := r.Form.Get("notrunc")
264
-		quiet := r.Form.Get("quiet")
265
-		n, err := strconv.Atoi(r.Form.Get("n"))
266
-		if err != nil {
267
-			n = -1
268
-		}
280
+	if err := srv.ContainerTag(name, repo, tag, force); err != nil {
281
+		http.Error(w, err.Error(), http.StatusInternalServerError)
282
+		return err
283
+	}
284
+	w.WriteHeader(http.StatusCreated)
285
+	return nil
286
+}
269 287
 
270
-		outs := srv.Containers(all, notrunc, quiet, n)
271
-		b, err := json.Marshal(outs)
272
-		if err != nil {
273
-			http.Error(w, err.Error(), http.StatusInternalServerError)
274
-		} else {
275
-			w.Header().Set("Content-Type", "application/json")
276
-			w.Write(b)
277
-		}
278
-	})
288
+func postCommit(srv *Server, w http.ResponseWriter, r *http.Request) error {
289
+	log.Println(r.Method, r.RequestURI)
290
+	if err := r.ParseForm(); err != nil {
291
+		http.Error(w, err.Error(), http.StatusInternalServerError)
292
+		return err
293
+	}
294
+	var config Config
295
+	if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
296
+		http.Error(w, err.Error(), http.StatusInternalServerError)
297
+		return err
298
+	}
299
+	repo := r.Form.Get("repo")
300
+	tag := r.Form.Get("tag")
301
+	container := r.Form.Get("container")
302
+	author := r.Form.Get("author")
303
+	comment := r.Form.Get("comment")
304
+	id, err := srv.ContainerCommit(container, repo, tag, author, comment, &config)
305
+	if err != nil {
306
+		httpError(w, err)
307
+		return err
308
+	}
309
+	b, err := json.Marshal(ApiId{id})
310
+	if err != nil {
311
+		http.Error(w, err.Error(), http.StatusInternalServerError)
312
+		return err
313
+	} else {
314
+		w.Header().Set("Content-Type", "application/json")
315
+		w.Write(b)
316
+	}
317
+	return nil
318
+}
279 319
 
280
-	r.Path("/images/{name:.*}/tag").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
281
-		log.Println(r.Method, r.RequestURI)
282
-		if err := r.ParseForm(); err != nil {
283
-			http.Error(w, err.Error(), http.StatusInternalServerError)
284
-			return
285
-		}
286
-		repo := r.Form.Get("repo")
287
-		tag := r.Form.Get("tag")
288
-		vars := mux.Vars(r)
289
-		name := vars["name"]
290
-		var force bool
291
-		if r.Form.Get("force") == "1" {
292
-			force = true
293
-		}
320
+func postImages(srv *Server, w http.ResponseWriter, r *http.Request) error {
321
+	log.Println(r.Method, r.RequestURI)
322
+	if err := r.ParseForm(); err != nil {
323
+		http.Error(w, err.Error(), http.StatusInternalServerError)
324
+		return err
325
+	}
294 326
 
295
-		if err := srv.ContainerTag(name, repo, tag, force); err != nil {
296
-			http.Error(w, err.Error(), http.StatusInternalServerError)
297
-			return
298
-		}
299
-		w.WriteHeader(http.StatusCreated)
300
-	})
327
+	src := r.Form.Get("fromSrc")
328
+	image := r.Form.Get("fromImage")
329
+	repo := r.Form.Get("repo")
330
+	tag := r.Form.Get("tag")
301 331
 
302
-	r.Path("/commit").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
303
-		log.Println(r.Method, r.RequestURI)
304
-		if err := r.ParseForm(); err != nil {
305
-			http.Error(w, err.Error(), http.StatusInternalServerError)
306
-			return
307
-		}
308
-		var config Config
309
-		if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
310
-			http.Error(w, err.Error(), http.StatusInternalServerError)
311
-			return
332
+	file, rwc, err := hijackServer(w)
333
+	if file != nil {
334
+		defer file.Close()
335
+	}
336
+	if rwc != nil {
337
+		defer rwc.Close()
338
+	}
339
+	if err != nil {
340
+		httpError(w, err)
341
+		return err
342
+	}
343
+	fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
344
+	if image != "" { //pull
345
+		registry := r.Form.Get("registry")
346
+		if err := srv.ImagePull(image, tag, registry, file); err != nil {
347
+			fmt.Fprintf(file, "Error: %s\n", err)
348
+			return err
312 349
 		}
313
-		repo := r.Form.Get("repo")
314
-		tag := r.Form.Get("tag")
315
-		container := r.Form.Get("container")
316
-		author := r.Form.Get("author")
317
-		comment := r.Form.Get("comment")
318
-		id, err := srv.ContainerCommit(container, repo, tag, author, comment, &config)
319
-		if err != nil {
320
-			httpError(w, err)
321
-			return
350
+	} else { //import
351
+		if err := srv.ImageImport(src, repo, tag, file); err != nil {
352
+			fmt.Fprintf(file, "Error: %s\n", err)
353
+			return err
322 354
 		}
323
-		b, err := json.Marshal(ApiId{id})
324
-		if err != nil {
325
-			http.Error(w, err.Error(), http.StatusInternalServerError)
326
-		} else {
327
-			w.Header().Set("Content-Type", "application/json")
328
-			w.Write(b)
329
-		}
330
-	})
355
+	}
356
+	return nil
357
+}
331 358
 
332
-	r.Path("/images").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
333
-		log.Println(r.Method, r.RequestURI)
334
-		if err := r.ParseForm(); err != nil {
335
-			http.Error(w, err.Error(), http.StatusInternalServerError)
336
-			return
337
-		}
359
+func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request) error {
360
+	log.Println(r.Method, r.RequestURI)
361
+	if err := r.ParseForm(); err != nil {
362
+		http.Error(w, err.Error(), http.StatusInternalServerError)
363
+		return err
364
+	}
338 365
 
339
-		src := r.Form.Get("fromSrc")
340
-		image := r.Form.Get("fromImage")
341
-		repo := r.Form.Get("repo")
342
-		tag := r.Form.Get("tag")
366
+	term := r.Form.Get("term")
367
+	outs, err := srv.ImagesSearch(term)
368
+	if err != nil {
369
+		httpError(w, err)
370
+		return err
371
+	}
372
+	b, err := json.Marshal(outs)
373
+	if err != nil {
374
+		http.Error(w, err.Error(), http.StatusInternalServerError)
375
+		return err
376
+	} else {
377
+		w.Header().Set("Content-Type", "application/json")
378
+		w.Write(b)
379
+	}
380
+	return nil
381
+}
343 382
 
344
-		file, rwc, err := hijackServer(w)
345
-		if file != nil {
346
-			defer file.Close()
347
-		}
348
-		if rwc != nil {
349
-			defer rwc.Close()
350
-		}
351
-		if err != nil {
352
-			httpError(w, err)
353
-			return
354
-		}
355
-		fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
356
-		if image != "" { //pull
357
-			registry := r.Form.Get("registry")
358
-			if err := srv.ImagePull(image, tag, registry, file); err != nil {
359
-				fmt.Fprintln(file, "Error: "+err.Error())
360
-			}
361
-		} else { //import
362
-			if err := srv.ImageImport(src, repo, tag, file); err != nil {
363
-				fmt.Fprintln(file, "Error: "+err.Error())
364
-			}
365
-		}
366
-	})
383
+func postImagesInsert(srv *Server, w http.ResponseWriter, r *http.Request) error {
384
+	log.Println(r.Method, r.RequestURI)
385
+	if err := r.ParseForm(); err != nil {
386
+		http.Error(w, err.Error(), http.StatusInternalServerError)
387
+		return err
388
+	}
367 389
 
368
-	r.Path("/images/search").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
369
-		log.Println(r.Method, r.RequestURI)
370
-		if err := r.ParseForm(); err != nil {
371
-			http.Error(w, err.Error(), http.StatusInternalServerError)
372
-			return
373
-		}
390
+	url := r.Form.Get("url")
391
+	path := r.Form.Get("path")
392
+	vars := mux.Vars(r)
393
+	name := vars["name"]
374 394
 
375
-		term := r.Form.Get("term")
376
-		outs, err := srv.ImagesSearch(term)
377
-		if err != nil {
378
-			httpError(w, err)
379
-			return
380
-		}
381
-		b, err := json.Marshal(outs)
382
-		if err != nil {
383
-			http.Error(w, err.Error(), http.StatusInternalServerError)
384
-		} else {
385
-			w.Header().Set("Content-Type", "application/json")
386
-			w.Write(b)
387
-		}
388
-	})
395
+	file, rwc, err := hijackServer(w)
396
+	if file != nil {
397
+		defer file.Close()
398
+	}
399
+	if rwc != nil {
400
+		defer rwc.Close()
401
+	}
402
+	if err != nil {
403
+		httpError(w, err)
404
+		return err
405
+	}
406
+	fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
407
+	if err := srv.ImageInsert(name, url, path, file); err != nil {
408
+		fmt.Fprintln(file, "Error: "+err.Error())
409
+	}
410
+	return nil
411
+}
389 412
 
390
-	r.Path("/images/{name:*.}/insert").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
391
-		log.Println(r.Method, r.RequestURI)
392
-		if err := r.ParseForm(); err != nil {
393
-			http.Error(w, err.Error(), http.StatusInternalServerError)
394
-			return
395
-		}
413
+func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request) error {
414
+	log.Println(r.Method, r.RequestURI)
415
+	if err := r.ParseForm(); err != nil {
416
+		http.Error(w, err.Error(), http.StatusInternalServerError)
417
+		return err
418
+	}
396 419
 
397
-		url := r.Form.Get("url")
398
-		path := r.Form.Get("path")
399
-		vars := mux.Vars(r)
400
-		name := vars["name"]
420
+	registry := r.Form.Get("registry")
401 421
 
402
-		file, rwc, err := hijackServer(w)
403
-		if file != nil {
404
-			defer file.Close()
405
-		}
406
-		if rwc != nil {
407
-			defer rwc.Close()
408
-		}
409
-		if err != nil {
410
-			httpError(w, err)
411
-			return
412
-		}
413
-		fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
414
-		if err := srv.ImageInsert(name, url, path, file); err != nil {
415
-			fmt.Fprintln(file, "Error: "+err.Error())
416
-		}
417
-	})
418
-	r.Path("/images/{name:*.}/push").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
419
-		log.Println(r.Method, r.RequestURI)
420
-		if err := r.ParseForm(); err != nil {
421
-			http.Error(w, err.Error(), http.StatusInternalServerError)
422
-			return
423
-		}
422
+	vars := mux.Vars(r)
423
+	name := vars["name"]
424 424
 
425
-		registry := r.Form.Get("registry")
425
+	file, rwc, err := hijackServer(w)
426
+	if file != nil {
427
+		defer file.Close()
428
+	}
429
+	if rwc != nil {
430
+		defer rwc.Close()
431
+	}
432
+	if err != nil {
433
+		httpError(w, err)
434
+		return err
435
+	}
436
+	fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
437
+	if err := srv.ImagePush(name, registry, file); err != nil {
438
+		fmt.Fprintln(file, "Error: "+err.Error())
439
+	}
440
+	return nil
441
+}
426 442
 
427
-		vars := mux.Vars(r)
428
-		name := vars["name"]
443
+func postBuild(srv *Server, w http.ResponseWriter, r *http.Request) error {
444
+	log.Println(r.Method, r.RequestURI)
429 445
 
430
-		file, rwc, err := hijackServer(w)
431
-		if file != nil {
432
-			defer file.Close()
433
-		}
434
-		if rwc != nil {
435
-			defer rwc.Close()
436
-		}
437
-		if err != nil {
438
-			httpError(w, err)
439
-			return
440
-		}
441
-		fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
442
-		if err := srv.ImagePush(name, registry, file); err != nil {
443
-			fmt.Fprintln(file, "Error: "+err.Error())
444
-		}
445
-	})
446
+	file, rwc, err := hijackServer(w)
447
+	if file != nil {
448
+		defer file.Close()
449
+	}
450
+	if rwc != nil {
451
+		defer rwc.Close()
452
+	}
453
+	if err != nil {
454
+		httpError(w, err)
455
+		return err
456
+	}
457
+	fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
458
+	if err := srv.ImageCreateFormFile(file); err != nil {
459
+		fmt.Fprintln(file, "Error: "+err.Error())
460
+	}
461
+	return nil
462
+}
446 463
 
447
-	r.Path("/build").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
448
-		log.Println(r.Method, r.RequestURI)
464
+func postContainers(srv *Server, w http.ResponseWriter, r *http.Request) error {
465
+	log.Println(r.Method, r.RequestURI)
466
+	var config Config
467
+	if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
468
+		http.Error(w, err.Error(), http.StatusInternalServerError)
469
+		return err
470
+	}
471
+	id, memoryW, swapW, err := srv.ContainerCreate(config)
472
+	if err != nil {
473
+		httpError(w, err)
474
+		return err
475
+	}
476
+	var out ApiRun
477
+	out.Id = id
478
+	if memoryW {
479
+		out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
480
+	}
481
+	if swapW {
482
+		out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.")
483
+	}
484
+	b, err := json.Marshal(out)
485
+	if err != nil {
486
+		http.Error(w, err.Error(), http.StatusInternalServerError)
487
+		return err
488
+	} else {
489
+		w.Header().Set("Content-Type", "application/json")
490
+		w.Write(b)
491
+	}
492
+	return nil
493
+}
449 494
 
450
-		file, rwc, err := hijackServer(w)
451
-		if file != nil {
452
-			defer file.Close()
453
-		}
454
-		if rwc != nil {
455
-			defer rwc.Close()
456
-		}
457
-		if err != nil {
458
-			httpError(w, err)
459
-			return
460
-		}
461
-		fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
462
-		if err := srv.ImageCreateFormFile(file); err != nil {
463
-			fmt.Fprintln(file, "Error: "+err.Error())
464
-		}
465
-	})
495
+func postContainersRestart(srv *Server, w http.ResponseWriter, r *http.Request) error {
496
+	log.Println(r.Method, r.RequestURI)
497
+	if err := r.ParseForm(); err != nil {
498
+		http.Error(w, err.Error(), http.StatusInternalServerError)
499
+		return err
500
+	}
501
+	t, err := strconv.Atoi(r.Form.Get("t"))
502
+	if err != nil || t < 0 {
503
+		t = 10
504
+	}
505
+	vars := mux.Vars(r)
506
+	name := vars["name"]
507
+	if err := srv.ContainerRestart(name, t); err != nil {
508
+		httpError(w, err)
509
+		return err
510
+	} else {
511
+		w.WriteHeader(http.StatusOK)
512
+	}
513
+	return nil
514
+}
466 515
 
467
-	r.Path("/containers").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
468
-		log.Println(r.Method, r.RequestURI)
469
-		var config Config
470
-		if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
471
-			http.Error(w, err.Error(), http.StatusInternalServerError)
472
-			return
473
-		}
474
-		id, memoryW, swapW, err := srv.ContainerCreate(config)
475
-		if err != nil {
476
-			httpError(w, err)
477
-			return
478
-		}
479
-		var out ApiRun
480
-		out.Id = id
481
-		if memoryW {
482
-			out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
483
-		}
484
-		if swapW {
485
-			out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.")
486
-		}
487
-		b, err := json.Marshal(out)
488
-		if err != nil {
489
-			http.Error(w, err.Error(), http.StatusInternalServerError)
490
-		} else {
491
-			w.Header().Set("Content-Type", "application/json")
492
-			w.Write(b)
493
-		}
494
-	})
516
+func deleteContainers(srv *Server, w http.ResponseWriter, r *http.Request) error {
517
+	log.Println(r.Method, r.RequestURI)
518
+	if err := r.ParseForm(); err != nil {
519
+		http.Error(w, err.Error(), http.StatusInternalServerError)
520
+		return err
521
+	}
522
+	vars := mux.Vars(r)
523
+	name := vars["name"]
524
+	var v bool
525
+	if r.Form.Get("v") == "1" {
526
+		v = true
527
+	}
528
+	if err := srv.ContainerDestroy(name, v); err != nil {
529
+		httpError(w, err)
530
+		return err
531
+	} else {
532
+		w.WriteHeader(http.StatusOK)
533
+	}
534
+	return nil
535
+}
495 536
 
496
-	r.Path("/containers/{name:.*}/restart").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
497
-		log.Println(r.Method, r.RequestURI)
498
-		if err := r.ParseForm(); err != nil {
499
-			http.Error(w, err.Error(), http.StatusInternalServerError)
500
-			return
501
-		}
502
-		t, err := strconv.Atoi(r.Form.Get("t"))
503
-		if err != nil || t < 0 {
504
-			t = 10
505
-		}
506
-		vars := mux.Vars(r)
507
-		name := vars["name"]
508
-		if err := srv.ContainerRestart(name, t); err != nil {
509
-			httpError(w, err)
510
-		} else {
511
-			w.WriteHeader(http.StatusOK)
512
-		}
513
-	})
537
+func deleteImages(srv *Server, w http.ResponseWriter, r *http.Request) error {
538
+	log.Println(r.Method, r.RequestURI)
539
+	vars := mux.Vars(r)
540
+	name := vars["name"]
541
+	if err := srv.ImageDelete(name); err != nil {
542
+		httpError(w, err)
543
+		return err
544
+	} else {
545
+		w.WriteHeader(http.StatusOK)
546
+	}
547
+	return nil
548
+}
514 549
 
515
-	r.Path("/containers/{name:.*}").Methods("DELETE").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
516
-		log.Println(r.Method, r.RequestURI)
517
-		if err := r.ParseForm(); err != nil {
518
-			http.Error(w, err.Error(), http.StatusInternalServerError)
519
-			return
520
-		}
521
-		vars := mux.Vars(r)
522
-		name := vars["name"]
523
-		var v bool
524
-		if r.Form.Get("v") == "1" {
525
-			v = true
526
-		}
527
-		if err := srv.ContainerDestroy(name, v); err != nil {
528
-			httpError(w, err)
529
-		} else {
530
-			w.WriteHeader(http.StatusOK)
531
-		}
532
-	})
550
+func postContainersStart(srv *Server, w http.ResponseWriter, r *http.Request) error {
551
+	log.Println(r.Method, r.RequestURI)
552
+	vars := mux.Vars(r)
553
+	name := vars["name"]
554
+	if err := srv.ContainerStart(name); err != nil {
555
+		httpError(w, err)
556
+		return err
557
+	} else {
558
+		w.WriteHeader(http.StatusOK)
559
+	}
560
+	return nil
561
+}
533 562
 
534
-	r.Path("/images/{name:.*}").Methods("DELETE").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
535
-		log.Println(r.Method, r.RequestURI)
536
-		vars := mux.Vars(r)
537
-		name := vars["name"]
538
-		if err := srv.ImageDelete(name); err != nil {
539
-			httpError(w, err)
540
-		} else {
541
-			w.WriteHeader(http.StatusOK)
542
-		}
543
-	})
563
+func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request) error {
564
+	log.Println(r.Method, r.RequestURI)
565
+	if err := r.ParseForm(); err != nil {
566
+		http.Error(w, err.Error(), http.StatusInternalServerError)
567
+		return err
568
+	}
569
+	t, err := strconv.Atoi(r.Form.Get("t"))
570
+	if err != nil || t < 0 {
571
+		t = 10
572
+	}
573
+	vars := mux.Vars(r)
574
+	name := vars["name"]
544 575
 
545
-	r.Path("/containers/{name:.*}/start").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
546
-		log.Println(r.Method, r.RequestURI)
547
-		vars := mux.Vars(r)
548
-		name := vars["name"]
549
-		if err := srv.ContainerStart(name); err != nil {
550
-			httpError(w, err)
551
-		} else {
552
-			w.WriteHeader(http.StatusOK)
553
-		}
554
-	})
576
+	if err := srv.ContainerStop(name, t); err != nil {
577
+		httpError(w, err)
578
+		return err
579
+	} else {
580
+		w.WriteHeader(http.StatusOK)
581
+	}
582
+	return nil
583
+}
555 584
 
556
-	r.Path("/containers/{name:.*}/stop").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
557
-		log.Println(r.Method, r.RequestURI)
558
-		if err := r.ParseForm(); err != nil {
559
-			http.Error(w, err.Error(), http.StatusInternalServerError)
560
-			return
561
-		}
562
-		t, err := strconv.Atoi(r.Form.Get("t"))
563
-		if err != nil || t < 0 {
564
-			t = 10
565
-		}
566
-		vars := mux.Vars(r)
567
-		name := vars["name"]
585
+func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request) error {
586
+	log.Println(r.Method, r.RequestURI)
587
+	vars := mux.Vars(r)
588
+	name := vars["name"]
589
+	status, err := srv.ContainerWait(name)
590
+	if err != nil {
591
+		httpError(w, err)
592
+		return err
593
+	}
594
+	b, err := json.Marshal(ApiWait{status})
595
+	if err != nil {
596
+		http.Error(w, err.Error(), http.StatusInternalServerError)
597
+		return err
598
+	} else {
599
+		w.Header().Set("Content-Type", "application/json")
600
+		w.Write(b)
601
+	}
602
+	return nil
603
+}
568 604
 
569
-		if err := srv.ContainerStop(name, t); err != nil {
570
-			httpError(w, err)
571
-		} else {
572
-			w.WriteHeader(http.StatusOK)
573
-		}
574
-	})
605
+func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request) error {
606
+	log.Println(r.Method, r.RequestURI)
607
+	if err := r.ParseForm(); err != nil {
608
+		http.Error(w, err.Error(), http.StatusInternalServerError)
609
+		return err
610
+	}
611
+	logs := r.Form.Get("logs")
612
+	stream := r.Form.Get("stream")
613
+	stdin := r.Form.Get("stdin")
614
+	stdout := r.Form.Get("stdout")
615
+	stderr := r.Form.Get("stderr")
616
+	vars := mux.Vars(r)
617
+	name := vars["name"]
618
+
619
+	file, rwc, err := hijackServer(w)
620
+	if file != nil {
621
+		defer file.Close()
622
+	}
623
+	if rwc != nil {
624
+		defer rwc.Close()
625
+	}
626
+	if err != nil {
627
+		httpError(w, err)
628
+		return err
629
+	}
575 630
 
576
-	r.Path("/containers/{name:.*}/wait").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
577
-		log.Println(r.Method, r.RequestURI)
578
-		vars := mux.Vars(r)
579
-		name := vars["name"]
580
-		status, err := srv.ContainerWait(name)
581
-		if err != nil {
582
-			httpError(w, err)
583
-			return
584
-		}
585
-		b, err := json.Marshal(ApiWait{status})
586
-		if err != nil {
587
-			http.Error(w, err.Error(), http.StatusInternalServerError)
588
-		} else {
589
-			w.Header().Set("Content-Type", "application/json")
590
-			w.Write(b)
591
-		}
592
-	})
631
+	fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
632
+	if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, file); err != nil {
633
+		fmt.Fprintf(file, "Error: %s\n", err)
634
+		return err
635
+	}
636
+	return nil
637
+}
593 638
 
594
-	r.Path("/containers/{name:.*}/attach").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
595
-		log.Println(r.Method, r.RequestURI)
596
-		if err := r.ParseForm(); err != nil {
597
-			http.Error(w, err.Error(), http.StatusInternalServerError)
598
-			return
599
-		}
600
-		logs := r.Form.Get("logs")
601
-		stream := r.Form.Get("stream")
602
-		stdin := r.Form.Get("stdin")
603
-		stdout := r.Form.Get("stdout")
604
-		stderr := r.Form.Get("stderr")
605
-		vars := mux.Vars(r)
606
-		name := vars["name"]
639
+func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request) error {
640
+	log.Println(r.Method, r.RequestURI)
641
+	vars := mux.Vars(r)
642
+	name := vars["name"]
607 643
 
608
-		file, rwc, err := hijackServer(w)
609
-		if file != nil {
610
-			defer file.Close()
611
-		}
612
-		if rwc != nil {
613
-			defer rwc.Close()
614
-		}
615
-		if err != nil {
616
-			httpError(w, err)
617
-			return
618
-		}
644
+	container, err := srv.ContainerInspect(name)
645
+	if err != nil {
646
+		httpError(w, err)
647
+		return err
648
+	}
649
+	b, err := json.Marshal(container)
650
+	if err != nil {
651
+		http.Error(w, err.Error(), http.StatusInternalServerError)
652
+		return err
653
+	} else {
654
+		w.Header().Set("Content-Type", "application/json")
655
+		w.Write(b)
656
+	}
657
+	return nil
658
+}
619 659
 
620
-		fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
621
-		if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, file); err != nil {
622
-			fmt.Fprintln(file, "Error: "+err.Error())
623
-		}
624
-	})
660
+func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request) error {
661
+	log.Println(r.Method, r.RequestURI)
662
+	vars := mux.Vars(r)
663
+	name := vars["name"]
625 664
 
626
-	r.Path("/containers/{name:.*}").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
627
-		log.Println(r.Method, r.RequestURI)
628
-		vars := mux.Vars(r)
629
-		name := vars["name"]
665
+	image, err := srv.ImageInspect(name)
666
+	if err != nil {
667
+		httpError(w, err)
668
+		return err
669
+	}
670
+	b, err := json.Marshal(image)
671
+	if err != nil {
672
+		http.Error(w, err.Error(), http.StatusInternalServerError)
673
+		return err
674
+	} else {
675
+		w.Header().Set("Content-Type", "application/json")
676
+		w.Write(b)
677
+	}
678
+	return nil
679
+}
630 680
 
631
-		container, err := srv.ContainerInspect(name)
632
-		if err != nil {
633
-			httpError(w, err)
634
-			return
635
-		}
636
-		b, err := json.Marshal(container)
637
-		if err != nil {
638
-			http.Error(w, err.Error(), http.StatusInternalServerError)
639
-		} else {
640
-			w.Header().Set("Content-Type", "application/json")
641
-			w.Write(b)
642
-		}
643
-	})
681
+func wrap(fct func(*Server, http.ResponseWriter, *http.Request) error, w http.ResponseWriter, r *http.Request, srv *Server, method, route string) {
682
+	if err := fct(srv, w, r); err != nil {
683
+		Debugf("Error: %s %s: %s", method, route, err)
684
+	}
685
+}
644 686
 
645
-	r.Path("/images/{name:.*}").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
646
-		log.Println(r.Method, r.RequestURI)
647
-		vars := mux.Vars(r)
648
-		name := vars["name"]
687
+func ListenAndServe(addr string, srv *Server) error {
688
+	r := mux.NewRouter()
689
+	log.Printf("Listening for HTTP on %s\n", addr)
649 690
 
650
-		image, err := srv.ImageInspect(name)
651
-		if err != nil {
652
-			httpError(w, err)
653
-			return
654
-		}
655
-		b, err := json.Marshal(image)
656
-		if err != nil {
657
-			http.Error(w, err.Error(), http.StatusInternalServerError)
658
-		} else {
659
-			w.Header().Set("Content-Type", "application/json")
660
-			w.Write(b)
691
+	m := map[string]map[string]func(*Server, http.ResponseWriter, *http.Request) error{
692
+		"GET": {
693
+			"/auth":                         getAuth,
694
+			"/version":                      getVersion,
695
+			"/containers/{name:.*}/export":  getContainersExport,
696
+			"/images":                       getImages,
697
+			"/info":                         getInfo,
698
+			"/images/{name:.*}/history":     getImagesHistory,
699
+			"/containers/{name:.*}/changes": getContainersChanges,
700
+			"/containers/{name:.*}/port":    getContainersPort,
701
+			"/containers":                   getContainers,
702
+			"/images/search":                getImagesSearch,
703
+			"/containers/{name:.*}":         getContainersByName,
704
+			"/images/{name:.*}":             getImagesByName,
705
+		},
706
+		"POST": {
707
+			"/auth": postAuth,
708
+			"/containers/{name:.*}/kill":    postContainersKill,
709
+			"/images/{name:.*}/tag":         postImagesTag,
710
+			"/commit":                       postCommit,
711
+			"/images":                       postImages,
712
+			"/images/{name:*.}/insert":      postImagesInsert,
713
+			"/images/{name:*.}/push":        postImagesPush,
714
+			"/postBuild":                    postBuild,
715
+			"/postContainers":               postContainers,
716
+			"/containers/{name:.*}/restart": postContainersRestart,
717
+			"/containers/{name:.*}/start":   postContainersStart,
718
+			"/containers/{name:.*}/stop":    postContainersStop,
719
+			"/containers/{name:.*}/wait":    postContainersWait,
720
+			"/containers/{name:.*}/attach":  postContainersAttach,
721
+		},
722
+		"DELETE": {
723
+			"/containers/{name:.*}": deleteContainers,
724
+			"/images/{name:.*}":     deleteImages,
725
+		},
726
+	}
727
+
728
+	for method, routes := range m {
729
+		for route, fct := range routes {
730
+			Debugf("Registering %s, %s", method, route)
731
+			// NOTE: scope issue, make sure the variables are local and won't be changed
732
+			localRoute := route
733
+			localMethod := method
734
+			localFct := fct
735
+			r.Path(localRoute).Methods(localMethod).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
736
+				Debugf("Calling %s %s", localMethod, localRoute)
737
+				localFct(srv, w, r)
738
+			})
661 739
 		}
662
-	})
740
+	}
663 741
 
664 742
 	return http.ListenAndServe(addr, r)
665 743
 }
... ...
@@ -35,8 +35,10 @@ func checkRemoteVersion() error {
35 35
 	}
36 36
 
37 37
 	var out ApiVersion
38
+
38 39
 	err = json.Unmarshal(body, &out)
39 40
 	if err != nil {
41
+		Debugf("Error unmarshal: body: %s, err: %s\n", body, err)
40 42
 		return err
41 43
 	}
42 44
 	if out.Version != VERSION {
... ...
@@ -323,6 +325,7 @@ func CmdVersion(args ...string) error {
323 323
 	var out ApiVersion
324 324
 	err = json.Unmarshal(body, &out)
325 325
 	if err != nil {
326
+		Debugf("Error unmarshal: body: %s, err: %s\n", body, err)
326 327
 		return err
327 328
 	}
328 329
 	fmt.Println("Version:", out.Version)
... ...
@@ -1213,7 +1216,7 @@ func hijack(method, path string, setRawTerminal bool) error {
1213 1213
 	sendStdin := Go(func() error {
1214 1214
 		_, err := io.Copy(rwc, os.Stdin)
1215 1215
 		if err := rwc.(*net.TCPConn).CloseWrite(); err != nil {
1216
-			fmt.Fprintf(os.Stderr, "Couldn't send EOF: "+err.Error())
1216
+			fmt.Fprintf(os.Stderr, "Couldn't send EOF: %s\n", err)
1217 1217
 		}
1218 1218
 		return err
1219 1219
 	})
... ...
@@ -316,7 +316,7 @@ func (srv *Server) ImagePush(name, registry string, file *os.File) error {
316 316
 	img, err := srv.runtime.graph.Get(name)
317 317
 	if err != nil {
318 318
 		Debugf("The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name]))
319
-		// If it fails, try to get the repository                                                                                                                      
319
+		// If it fails, try to get the repository
320 320
 		if localRepo, exists := srv.runtime.repositories.Repositories[name]; exists {
321 321
 			if err := srv.runtime.graph.PushRepository(file, name, localRepo, srv.runtime.authConfig); err != nil {
322 322
 				return err
... ...
@@ -350,8 +350,8 @@ func (srv *Server) ImageImport(src, repo, tag string, file *os.File) error {
350 350
 			u.Path = ""
351 351
 		}
352 352
 		fmt.Fprintln(file, "Downloading from", u)
353
-		// Download with curl (pretty progress bar)                                                                            
354
-		// If curl is not available, fallback to http.Get()                                                                    
353
+		// Download with curl (pretty progress bar)
354
+		// If curl is not available, fallback to http.Get()
355 355
 		resp, err = Download(u.String(), file)
356 356
 		if err != nil {
357 357
 			return err
... ...
@@ -362,7 +362,7 @@ func (srv *Server) ImageImport(src, repo, tag string, file *os.File) error {
362 362
 	if err != nil {
363 363
 		return err
364 364
 	}
365
-	// Optionally register the image at REPO/TAG                                                                                   
365
+	// Optionally register the image at REPO/TAG
366 366
 	if repo != "" {
367 367
 		if err := srv.runtime.repositories.Set(repo, tag, img.Id, true); err != nil {
368 368
 			return err