http.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. package engine
  2. import (
  3. "net/http"
  4. "path"
  5. )
  6. // ServeHTTP executes a job as specified by the http request `r`, and sends the
  7. // result as an http response.
  8. // This method allows an Engine instance to be passed as a standard http.Handler interface.
  9. //
  10. // Note that the protocol used in this method is a convenience wrapper and is not the canonical
  11. // implementation of remote job execution. This is because HTTP/1 does not handle stream multiplexing,
  12. // and so cannot differentiate stdout from stderr. Additionally, headers cannot be added to a response
  13. // once data has been written to the body, which makes it inconvenient to return metadata such
  14. // as the exit status.
  15. //
  16. func (eng *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  17. var (
  18. jobName = path.Base(r.URL.Path)
  19. jobArgs, exists = r.URL.Query()["a"]
  20. )
  21. if !exists {
  22. jobArgs = []string{}
  23. }
  24. w.Header().Set("Job-Name", jobName)
  25. for _, arg := range jobArgs {
  26. w.Header().Add("Job-Args", arg)
  27. }
  28. job := eng.Job(jobName, jobArgs...)
  29. job.Stdout.Add(w)
  30. job.Stderr.Add(w)
  31. // FIXME: distinguish job status from engine error in Run()
  32. // The former should be passed as a special header, the former
  33. // should cause a 500 status
  34. w.WriteHeader(http.StatusOK)
  35. // The exit status cannot be sent reliably with HTTP1, because headers
  36. // can only be sent before the body.
  37. // (we could possibly use http footers via chunked encoding, but I couldn't find
  38. // how to use them in net/http)
  39. job.Run()
  40. }