sender.go raw

   1  package adal
   2  
   3  // Copyright 2017 Microsoft Corporation
   4  //
   5  //  Licensed under the Apache License, Version 2.0 (the "License");
   6  //  you may not use this file except in compliance with the License.
   7  //  You may obtain a copy of the License at
   8  //
   9  //      http://www.apache.org/licenses/LICENSE-2.0
  10  //
  11  //  Unless required by applicable law or agreed to in writing, software
  12  //  distributed under the License is distributed on an "AS IS" BASIS,
  13  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14  //  See the License for the specific language governing permissions and
  15  //  limitations under the License.
  16  
  17  import (
  18  	"crypto/tls"
  19  	"net"
  20  	"net/http"
  21  	"net/http/cookiejar"
  22  	"sync"
  23  	"time"
  24  
  25  	"github.com/Azure/go-autorest/tracing"
  26  )
  27  
  28  const (
  29  	contentType      = "Content-Type"
  30  	mimeTypeFormPost = "application/x-www-form-urlencoded"
  31  )
  32  
  33  // DO NOT ACCESS THIS DIRECTLY.  go through sender()
  34  var defaultSender Sender
  35  var defaultSenderInit = &sync.Once{}
  36  
  37  // Sender is the interface that wraps the Do method to send HTTP requests.
  38  //
  39  // The standard http.Client conforms to this interface.
  40  type Sender interface {
  41  	Do(*http.Request) (*http.Response, error)
  42  }
  43  
  44  // SenderFunc is a method that implements the Sender interface.
  45  type SenderFunc func(*http.Request) (*http.Response, error)
  46  
  47  // Do implements the Sender interface on SenderFunc.
  48  func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
  49  	return sf(r)
  50  }
  51  
  52  // SendDecorator takes and possibly decorates, by wrapping, a Sender. Decorators may affect the
  53  // http.Request and pass it along or, first, pass the http.Request along then react to the
  54  // http.Response result.
  55  type SendDecorator func(Sender) Sender
  56  
  57  // CreateSender creates, decorates, and returns, as a Sender, the default http.Client.
  58  func CreateSender(decorators ...SendDecorator) Sender {
  59  	return DecorateSender(sender(), decorators...)
  60  }
  61  
  62  // DecorateSender accepts a Sender and a, possibly empty, set of SendDecorators, which is applies to
  63  // the Sender. Decorators are applied in the order received, but their affect upon the request
  64  // depends on whether they are a pre-decorator (change the http.Request and then pass it along) or a
  65  // post-decorator (pass the http.Request along and react to the results in http.Response).
  66  func DecorateSender(s Sender, decorators ...SendDecorator) Sender {
  67  	for _, decorate := range decorators {
  68  		s = decorate(s)
  69  	}
  70  	return s
  71  }
  72  
  73  func sender() Sender {
  74  	// note that we can't init defaultSender in init() since it will
  75  	// execute before calling code has had a chance to enable tracing
  76  	defaultSenderInit.Do(func() {
  77  		// copied from http.DefaultTransport with a TLS minimum version.
  78  		transport := &http.Transport{
  79  			Proxy: http.ProxyFromEnvironment,
  80  			DialContext: (&net.Dialer{
  81  				Timeout:   30 * time.Second,
  82  				KeepAlive: 30 * time.Second,
  83  			}).DialContext,
  84  			ForceAttemptHTTP2:     true,
  85  			MaxIdleConns:          100,
  86  			IdleConnTimeout:       90 * time.Second,
  87  			TLSHandshakeTimeout:   10 * time.Second,
  88  			ExpectContinueTimeout: 1 * time.Second,
  89  			TLSClientConfig: &tls.Config{
  90  				MinVersion: tls.VersionTLS12,
  91  			},
  92  		}
  93  		var roundTripper http.RoundTripper = transport
  94  		if tracing.IsEnabled() {
  95  			roundTripper = tracing.NewTransport(transport)
  96  		}
  97  		j, _ := cookiejar.New(nil)
  98  		defaultSender = &http.Client{Jar: j, Transport: roundTripper}
  99  	})
 100  	return defaultSender
 101  }
 102