github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edgemesh/pkg/protocol/http/http.go (about)

     1  package http
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"context"
     7  	"fmt"
     8  	"io"
     9  	"net"
    10  	"net/http"
    11  
    12  	"github.com/go-chassis/go-chassis/core/common"
    13  	"github.com/go-chassis/go-chassis/core/handler"
    14  	"github.com/go-chassis/go-chassis/core/invocation"
    15  	"k8s.io/klog"
    16  
    17  	"github.com/kubeedge/kubeedge/edgemesh/pkg/config"
    18  )
    19  
    20  type HTTP struct {
    21  	Conn         net.Conn
    22  	SvcNamespace string
    23  	SvcName      string
    24  	Port         int
    25  
    26  	req *http.Request
    27  }
    28  
    29  // Process handles http protocol
    30  func (p *HTTP) Process() {
    31  	defer p.Conn.Close()
    32  
    33  	for {
    34  		// parse http request
    35  		req, err := http.ReadRequest(bufio.NewReader(p.Conn))
    36  		if err != nil {
    37  			if err == io.EOF {
    38  				klog.Infof("[EdgeMesh] http client disconnected.")
    39  				return
    40  			}
    41  			klog.Errorf("[EdgeMesh] parse http request err: %v", err)
    42  			return
    43  		}
    44  
    45  		// http: Request.RequestURI can't be set in client requests
    46  		// just reset it before transport
    47  		req.RequestURI = ""
    48  
    49  		// create invocation
    50  		inv := invocation.New(context.Background())
    51  
    52  		// set invocation
    53  		inv.MicroServiceName = req.Host
    54  		inv.SourceServiceID = ""
    55  		inv.Protocol = "rest"
    56  		inv.Strategy = config.Config.LBStrategy
    57  		inv.Args = req
    58  		inv.Reply = &http.Response{}
    59  
    60  		// create handlerchain
    61  		c, err := handler.CreateChain(common.Consumer, "http", handler.Loadbalance, handler.Transport)
    62  		if err != nil {
    63  			klog.Errorf("[EdgeMesh] create http handlerchain error: %v", err)
    64  			return
    65  		}
    66  
    67  		// start to handle
    68  		p.req = req
    69  		c.Next(inv, p.responseCallback)
    70  	}
    71  }
    72  
    73  // responseCallback implements http handlerchain callback
    74  func (p *HTTP) responseCallback(data *invocation.Response) error {
    75  	var err error
    76  	var resp *http.Response
    77  	var respBytes []byte
    78  
    79  	// as a proxy server, make sure that edgemesh always response to a request
    80  	// send either the response of the real backend server or 503 back
    81  	if data.Err != nil {
    82  		klog.Errorf("[EdgeMesh] error in http handlerchain: %v", data.Err)
    83  		err = data.Err
    84  	} else {
    85  		if data.Result == nil {
    86  			klog.Errorf("[EdgeMesh] empty response from http handlerchain")
    87  			err = fmt.Errorf("empty response from http handlerchain")
    88  		} else {
    89  			var ok bool
    90  			resp, ok = data.Result.(*http.Response)
    91  			if !ok {
    92  				klog.Errorf("[EdgeMesh] http handlerchain result %+v not *http.Response type", data.Result)
    93  				err = fmt.Errorf("result not *http.Response type")
    94  			} else {
    95  				respBytes, err = httpResponseToBytes(resp)
    96  				if err != nil {
    97  					klog.Errorf("[EdgeMesh] convert http response to bytes err: %v", err)
    98  				} else {
    99  					// send response back
   100  					p.Conn.Write(respBytes)
   101  					return nil
   102  				}
   103  			}
   104  		}
   105  	}
   106  	// 503
   107  	resp = &http.Response{
   108  		Status:     fmt.Sprintf("%d %s", http.StatusServiceUnavailable, err),
   109  		StatusCode: http.StatusServiceUnavailable,
   110  		Proto:      p.req.Proto,
   111  		Request:    p.req,
   112  		Header:     make(http.Header, 0),
   113  	}
   114  	respBytes, _ = httpResponseToBytes(resp)
   115  	// send error response back
   116  	p.Conn.Write(respBytes)
   117  	return err
   118  }
   119  
   120  // httpResponseToBytes transforms http.Response to bytes
   121  func httpResponseToBytes(resp *http.Response) ([]byte, error) {
   122  	buf := new(bytes.Buffer)
   123  	if resp == nil {
   124  		return nil, fmt.Errorf("http response nil")
   125  	}
   126  	err := resp.Write(buf)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	return buf.Bytes(), nil
   131  }