2013-12-08 02:33:23 -05:00
|
|
|
package engine
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
2014-01-07 00:14:35 -05:00
|
|
|
"path"
|
2013-12-08 02:33:23 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// ServeHTTP executes a job as specified by the http request `r`, and sends the
|
|
|
|
// result as an http response.
|
|
|
|
// This method allows an Engine instance to be passed as a standard http.Handler interface.
|
|
|
|
//
|
2014-04-20 02:25:48 -04:00
|
|
|
// Note that the protocol used in this method is a convenience wrapper and is not the canonical
|
2013-12-08 02:33:23 -05:00
|
|
|
// implementation of remote job execution. This is because HTTP/1 does not handle stream multiplexing,
|
|
|
|
// and so cannot differentiate stdout from stderr. Additionally, headers cannot be added to a response
|
|
|
|
// once data has been written to the body, which makes it inconvenient to return metadata such
|
|
|
|
// as the exit status.
|
|
|
|
//
|
|
|
|
func (eng *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
2014-01-15 16:52:35 -05:00
|
|
|
var (
|
|
|
|
jobName = path.Base(r.URL.Path)
|
|
|
|
jobArgs, exists = r.URL.Query()["a"]
|
|
|
|
)
|
2013-12-08 02:33:23 -05:00
|
|
|
if !exists {
|
|
|
|
jobArgs = []string{}
|
|
|
|
}
|
|
|
|
w.Header().Set("Job-Name", jobName)
|
2014-01-07 00:14:35 -05:00
|
|
|
for _, arg := range jobArgs {
|
2013-12-08 02:33:23 -05:00
|
|
|
w.Header().Add("Job-Args", arg)
|
|
|
|
}
|
|
|
|
job := eng.Job(jobName, jobArgs...)
|
|
|
|
job.Stdout.Add(w)
|
|
|
|
job.Stderr.Add(w)
|
|
|
|
// FIXME: distinguish job status from engine error in Run()
|
|
|
|
// The former should be passed as a special header, the former
|
|
|
|
// should cause a 500 status
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
// The exit status cannot be sent reliably with HTTP1, because headers
|
|
|
|
// can only be sent before the body.
|
|
|
|
// (we could possibly use http footers via chunked encoding, but I couldn't find
|
|
|
|
// how to use them in net/http)
|
|
|
|
job.Run()
|
|
|
|
}
|