<commit_before>package service

import (
	"container/list"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/xtracdev/xavi/plugin"
	"github.com/xtracdev/xavi/plugin/timing"
	"golang.org/x/net/context"
	"io"
	"net/http"
	"strings"
)

//Service represents a runnable service
type Service interface {
	Run()
}

//Request handler has the configuration needed to build an http.Handler for a route and its chained plugins
type requestHandler struct {
	Transport    *http.Transport
	TLSTransport *http.Transport
	Backend      *backend
	PluginChain  *list.List
}

func backendName(name string) string {
	if strings.Contains(name, "backend") {
		return name
	} else {
		return name + "-backend"
	}
}

//Create a handler function from a requestHandler
func (rh *requestHandler) toContextHandlerFunc() func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {

		//Record call time contribution
		rt := timing.TimerFromContext(ctx)
		if rt == nil {
			http.Error(w, "No EndToEndTimer found in call context", http.StatusInternalServerError)
			return
		}

		timingContributor := rt.StartContributor(backendName(rh.Backend.Name))

		connectString, err := rh.Backend.getConnectAddress()
		if err != nil {
			http.Error(w, err.Error(), http.StatusServiceUnavailable)
			timingContributor.End(err)
			return
		}

		log.Debug("connect string for ", rh.Backend.Name, "is ", connectString)
		r.URL.Host = connectString
		r.Host = connectString

		log.Debug("invoke backend service")
		serviceName := timing.GetServiceNameFromContext(ctx)
		if serviceName == "" {
			serviceName = "backend-call"
		}

		r.URL.Scheme = "http"
		log.Debug("Determine transport")
		var transport = rh.getTransportForBackend(ctx)
		if transport == rh.TLSTransport {
			log.Debug("https transport")
			r.URL.Scheme = "https"
		}

		log.Debug(r.URL.Scheme, " transport for backend ", rh.Backend.Name)

		beTimer := timingContributor.StartServiceCall(serviceName, connectString)
		log.Debug("call service ", serviceName, " for backend ", rh.Backend.Name)
		resp, err := transport.RoundTrip(r)
		beTimer.End(err)
		if err != nil {
			log.Info(err.Error())
			w.WriteHeader(http.StatusServiceUnavailable)
			fmt.Fprintf(w, "Error: %v", err)
			timingContributor.End(err)
			return
		}

		log.Debug("backend service complete, copy backend response headers to response")
		for k, v := range resp.Header {
			for _, vv := range v {<commit_msg>Updated code to call using cancel and timeout aware ctxhttp.Do<commit_after>package service

import (
	"container/list"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/xtracdev/xavi/plugin"
	"github.com/xtracdev/xavi/plugin/timing"
	"golang.org/x/net/context"
	"golang.org/x/net/context/ctxhttp"
	"io"
	"net/http"
	"strings"
)

//Service represents a runnable service
type Service interface {
	Run()
}

//Request handler has the configuration needed to build an http.Handler for a route and its chained plugins
type requestHandler struct {
	Transport    *http.Transport
	TLSTransport *http.Transport
	Backend      *backend
	PluginChain  *list.List
}

func backendName(name string) string {
	if strings.Contains(name, "backend") {
		return name
	} else {
		return name + "-backend"
	}
}

//Create a handler function from a requestHandler
func (rh *requestHandler) toContextHandlerFunc() func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {

		//Record call time contribution
		rt := timing.TimerFromContext(ctx)
		if rt == nil {
			http.Error(w, "No EndToEndTimer found in call context", http.StatusInternalServerError)
			return
		}

		timingContributor := rt.StartContributor(backendName(rh.Backend.Name))

		connectString, err := rh.Backend.getConnectAddress()
		if err != nil {
			http.Error(w, err.Error(), http.StatusServiceUnavailable)
			timingContributor.End(err)
			return
		}

		log.Debug("connect string for ", rh.Backend.Name, "is ", connectString)
		r.URL.Host = connectString
		r.Host = connectString

		log.Debug("invoke backend service")
		serviceName := timing.GetServiceNameFromContext(ctx)
		if serviceName == "" {
			serviceName = "backend-call"
		}

		r.URL.Scheme = "http"
		log.Debug("Determine transport")
		var transport = rh.getTransportForBackend(ctx)
		if transport == rh.TLSTransport {
			log.Debug("https transport")
			r.URL.Scheme = "https"
		}

		log.Debug(r.URL.Scheme, " transport for backend ", rh.Backend.Name)

		beTimer := timingContributor.StartServiceCall(serviceName, connectString)
		log.Debug("call service ", serviceName, " for backend ", rh.Backend.Name)

		//resp, err := transport.RoundTrip(r)
		client := &http.Client{
			Transport: transport,
		}

		r.RequestURI = "" //Must clear when using http.Client
		resp, err := ctxhttp.Do(ctx, client, r)

		beTimer.End(err)
		if err != nil {
			log.Info(err.Error())
			w.WriteHeader(http.StatusServiceUnavailable)
			fmt.Fprintf(w, "Error: %v", err)
			timingContributor.End(err)
			return
		}

		log.Debug("backend service complete, copy backend response headers to response")
		for k, v := range resp.Header {
			for _, vv := range v {
{'fraction_non_alphanumeric': 0.12070619842640568, 'fraction_numerical': 0.0, 'mean_word_length': 4.079922027290448, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3365583', 'n_tokens_mistral': 1832, 'n_tokens_neox': 1674, 'n_words': 421}