]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/google.golang.org/api/transport/http/internal/propagation/http.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / google.golang.org / api / transport / http / internal / propagation / http.go
1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // +build go1.8
16
17 // Package propagation implements X-Cloud-Trace-Context header propagation used
18 // by Google Cloud products.
19 package propagation
20
21 import (
22 "encoding/binary"
23 "encoding/hex"
24 "fmt"
25 "net/http"
26 "strconv"
27 "strings"
28
29 "go.opencensus.io/trace"
30 "go.opencensus.io/trace/propagation"
31 )
32
33 const (
34 httpHeaderMaxSize = 200
35 httpHeader = `X-Cloud-Trace-Context`
36 )
37
38 var _ propagation.HTTPFormat = (*HTTPFormat)(nil)
39
40 // HTTPFormat implements propagation.HTTPFormat to propagate
41 // traces in HTTP headers for Google Cloud Platform and Stackdriver Trace.
42 type HTTPFormat struct{}
43
44 // SpanContextFromRequest extracts a Stackdriver Trace span context from incoming requests.
45 func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
46 h := req.Header.Get(httpHeader)
47 // See https://cloud.google.com/trace/docs/faq for the header HTTPFormat.
48 // Return if the header is empty or missing, or if the header is unreasonably
49 // large, to avoid making unnecessary copies of a large string.
50 if h == "" || len(h) > httpHeaderMaxSize {
51 return trace.SpanContext{}, false
52 }
53
54 // Parse the trace id field.
55 slash := strings.Index(h, `/`)
56 if slash == -1 {
57 return trace.SpanContext{}, false
58 }
59 tid, h := h[:slash], h[slash+1:]
60
61 buf, err := hex.DecodeString(tid)
62 if err != nil {
63 return trace.SpanContext{}, false
64 }
65 copy(sc.TraceID[:], buf)
66
67 // Parse the span id field.
68 spanstr := h
69 semicolon := strings.Index(h, `;`)
70 if semicolon != -1 {
71 spanstr, h = h[:semicolon], h[semicolon+1:]
72 }
73 sid, err := strconv.ParseUint(spanstr, 10, 64)
74 if err != nil {
75 return trace.SpanContext{}, false
76 }
77 binary.BigEndian.PutUint64(sc.SpanID[:], sid)
78
79 // Parse the options field, options field is optional.
80 if !strings.HasPrefix(h, "o=") {
81 return sc, true
82 }
83 o, err := strconv.ParseUint(h[2:], 10, 64)
84 if err != nil {
85 return trace.SpanContext{}, false
86 }
87 sc.TraceOptions = trace.TraceOptions(o)
88 return sc, true
89 }
90
91 // SpanContextToRequest modifies the given request to include a Stackdriver Trace header.
92 func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
93 sid := binary.BigEndian.Uint64(sc.SpanID[:])
94 header := fmt.Sprintf("%s/%d;o=%d", hex.EncodeToString(sc.TraceID[:]), sid, int64(sc.TraceOptions))
95 req.Header.Set(httpHeader, header)
96 }