github.com/kcmerrill/alfred@v0.0.0-20180727171036-06445dcb5e3d/pkg/alfred/http.task.go (about)

     1  package alfred
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"os"
     9  	"os/exec"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/gorilla/mux"
    14  )
    15  
    16  // HTTPTask contains all of our task information
    17  type HTTPTask struct {
    18  	context *Context
    19  	tasks   map[string]Task
    20  }
    21  
    22  func (h *HTTPTask) runner(resp http.ResponseWriter, req *http.Request) {
    23  	vars := mux.Vars(req)
    24  
    25  	if vars["task"] == "favicon.ico" {
    26  		return
    27  	}
    28  
    29  	url, name := TaskParser(vars["task"], "alfred:list")
    30  	if url != "" || name == "alfred:list" {
    31  		resp.WriteHeader(http.StatusBadRequest)
    32  		fmt.Fprintf(resp, "'"+vars["task"]+"' is invalid.")
    33  		return
    34  	}
    35  
    36  	args := strings.Split(vars["args"], "/")
    37  	outOK(vars["task"]+" started ["+strings.Join(args, ", ")+"]", "", h.context)
    38  	stdin, _ := ioutil.ReadAll(req.Body) //trimspace
    39  	cmd := exec.Command(os.Args[0], "--no-formatting", vars["task"])
    40  	cmdOutput, error := cmd.CombinedOutput()
    41  	cmd.Stdin = bytes.NewBuffer(stdin)
    42  
    43  	if error != nil {
    44  		resp.WriteHeader(http.StatusInternalServerError)
    45  		fmt.Fprintf(resp, string(cmdOutput))
    46  	} else {
    47  		resp.WriteHeader(http.StatusOK)
    48  		fmt.Fprintf(resp, string(cmdOutput))
    49  	}
    50  }
    51  
    52  func httptasks(task Task, context *Context, tasks map[string]Task) {
    53  	if task.HTTPTasks.Port == "" {
    54  		return
    55  	}
    56  
    57  	dir, _ := task.dir(context)
    58  
    59  	password := translate(evaluate(task.HTTPTasks.Password, dir), context)
    60  
    61  	addr := []string{"0.0.0.0", task.HTTPTasks.Port}
    62  	if strings.Contains(task.HTTPTasks.Port, ":") {
    63  		addr = strings.Split(task.HTTPTasks.Port, ":")
    64  	}
    65  
    66  	runner := &HTTPTask{
    67  		context: context,
    68  		tasks:   tasks,
    69  	}
    70  
    71  	r := mux.NewRouter()
    72  	r.HandleFunc(`/{task}/{args:[a-zA-Z0-9=\-\/\.]+}`, httptasksAuth(password, runner.runner)).Methods("GET", "POST")
    73  	r.HandleFunc(`/{task}`, httptasksAuth(password, runner.runner)).Methods("GET", "POST")
    74  	srv := &http.Server{
    75  		Handler:      r,
    76  		Addr:         strings.Join(addr, ":"),
    77  		WriteTimeout: 15 * time.Second,
    78  		ReadTimeout:  15 * time.Second,
    79  	}
    80  
    81  	outOK("serving "+dir, strings.Join(addr, ":"), context)
    82  	if err := srv.ListenAndServe(); err != nil {
    83  		outFail("serve", err.Error(), context)
    84  		task.Exit(context, tasks)
    85  	}
    86  }
    87  
    88  func httptasksAuth(password string, fn http.HandlerFunc) http.HandlerFunc {
    89  	return func(w http.ResponseWriter, r *http.Request) {
    90  		token, _, _ := r.BasicAuth()
    91  		if password != "" && password != token {
    92  			http.Error(w, `{"error": "unauthorized"}`, http.StatusUnauthorized)
    93  			return
    94  		}
    95  		fn(w, r)
    96  	}
    97  }