github.com/iron-io/functions@v0.0.0-20180820112432-d59d7d1c40b2/api/runner/protocol/http.go (about)

     1  package protocol
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"context"
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"net/http/httputil"
    11  	"time"
    12  
    13  	"github.com/iron-io/functions/api/models"
    14  	"github.com/iron-io/functions/api/runner/task"
    15  )
    16  
    17  // HTTPProtocol converts stdin/stdout streams into HTTP/1.1 compliant
    18  // communication. It relies on Content-Length to know when to stop reading from
    19  // containers stdout. It also mandates valid HTTP headers back and forth, thus
    20  // returning errors in case of parsing problems.
    21  type HTTPProtocol struct {
    22  	in  io.Writer
    23  	out io.Reader
    24  }
    25  
    26  func (p *HTTPProtocol) IsStreamable() bool {
    27  	return true
    28  }
    29  
    30  func (p *HTTPProtocol) Dispatch(ctx context.Context, t task.Request) error {
    31  	var retErr error
    32  	done := make(chan struct{})
    33  	go func() {
    34  		var body bytes.Buffer
    35  		io.Copy(&body, t.Config.Stdin)
    36  		req, err := http.NewRequest("GET", "/", &body)
    37  		if err != nil {
    38  			retErr = err
    39  			return
    40  		}
    41  		for k, v := range t.Config.Env {
    42  			req.Header.Set(k, v)
    43  		}
    44  		req.Header.Set("Content-Length", fmt.Sprint(body.Len()))
    45  		req.Header.Set("Task-ID", t.Config.ID)
    46  		raw, err := httputil.DumpRequest(req, true)
    47  		if err != nil {
    48  			retErr = err
    49  			return
    50  		}
    51  		p.in.Write(raw)
    52  
    53  		res, err := http.ReadResponse(bufio.NewReader(p.out), req)
    54  		if err != nil {
    55  			retErr = err
    56  			return
    57  		}
    58  
    59  		io.Copy(t.Config.Stdout, res.Body)
    60  		done <- struct{}{}
    61  	}()
    62  
    63  	timeout := time.After(t.Config.Timeout)
    64  
    65  	select {
    66  	case <-ctx.Done():
    67  		return ctx.Err()
    68  	case <-timeout:
    69  		return models.ErrRunnerTimeout
    70  	case <-done:
    71  		return retErr
    72  	}
    73  }