mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-03 19:17:29 -05:00 
			
		
		
		
	* Create request_id directive #1590 * Address Comments * Fix TestListenerAddrEqual * requestid: Add some tests * Address Comments by tobya * Address Comments
This commit is contained in:
		
							parent
							
								
									b0ab3d4281
								
							
						
					
					
						commit
						133ed18374
					
				@ -24,6 +24,7 @@ import (
 | 
				
			|||||||
	_ "github.com/mholt/caddy/caddyhttp/proxy"
 | 
						_ "github.com/mholt/caddy/caddyhttp/proxy"
 | 
				
			||||||
	_ "github.com/mholt/caddy/caddyhttp/push"
 | 
						_ "github.com/mholt/caddy/caddyhttp/push"
 | 
				
			||||||
	_ "github.com/mholt/caddy/caddyhttp/redirect"
 | 
						_ "github.com/mholt/caddy/caddyhttp/redirect"
 | 
				
			||||||
 | 
						_ "github.com/mholt/caddy/caddyhttp/requestid"
 | 
				
			||||||
	_ "github.com/mholt/caddy/caddyhttp/rewrite"
 | 
						_ "github.com/mholt/caddy/caddyhttp/rewrite"
 | 
				
			||||||
	_ "github.com/mholt/caddy/caddyhttp/root"
 | 
						_ "github.com/mholt/caddy/caddyhttp/root"
 | 
				
			||||||
	_ "github.com/mholt/caddy/caddyhttp/status"
 | 
						_ "github.com/mholt/caddy/caddyhttp/status"
 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,7 @@ import (
 | 
				
			|||||||
// ensure that the standard plugins are in fact plugged in
 | 
					// ensure that the standard plugins are in fact plugged in
 | 
				
			||||||
// and registered properly; this is a quick/naive way to do it.
 | 
					// and registered properly; this is a quick/naive way to do it.
 | 
				
			||||||
func TestStandardPlugins(t *testing.T) {
 | 
					func TestStandardPlugins(t *testing.T) {
 | 
				
			||||||
	numStandardPlugins := 31 // importing caddyhttp plugs in this many plugins
 | 
						numStandardPlugins := 32 // importing caddyhttp plugs in this many plugins
 | 
				
			||||||
	s := caddy.DescribePlugins()
 | 
						s := caddy.DescribePlugins()
 | 
				
			||||||
	if got, want := strings.Count(s, "\n"), numStandardPlugins+5; got != want {
 | 
						if got, want := strings.Count(s, "\n"), numStandardPlugins+5; got != want {
 | 
				
			||||||
		t.Errorf("Expected all standard plugins to be plugged in, got:\n%s", s)
 | 
							t.Errorf("Expected all standard plugins to be plugged in, got:\n%s", s)
 | 
				
			||||||
 | 
				
			|||||||
@ -205,4 +205,7 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// MitmCtxKey is the key for the result of MITM detection
 | 
						// MitmCtxKey is the key for the result of MITM detection
 | 
				
			||||||
	MitmCtxKey caddy.CtxKey = "mitm"
 | 
						MitmCtxKey caddy.CtxKey = "mitm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RequestIDCtxKey is the key for the U4 UUID value
 | 
				
			||||||
 | 
						RequestIDCtxKey caddy.CtxKey = "request_id"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
@ -443,6 +443,7 @@ var directives = []string{
 | 
				
			|||||||
	// services/utilities, or other directives that don't necessarily inject handlers
 | 
						// services/utilities, or other directives that don't necessarily inject handlers
 | 
				
			||||||
	"startup",
 | 
						"startup",
 | 
				
			||||||
	"shutdown",
 | 
						"shutdown",
 | 
				
			||||||
 | 
						"requestid",
 | 
				
			||||||
	"realip", // github.com/captncraig/caddy-realip
 | 
						"realip", // github.com/captncraig/caddy-realip
 | 
				
			||||||
	"git",    // github.com/abiosoft/caddy-git
 | 
						"git",    // github.com/abiosoft/caddy-git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -243,6 +243,9 @@ func (r *replacer) getSubstitution(key string) string {
 | 
				
			|||||||
	case "{path_escaped}":
 | 
						case "{path_escaped}":
 | 
				
			||||||
		u, _ := r.request.Context().Value(OriginalURLCtxKey).(url.URL)
 | 
							u, _ := r.request.Context().Value(OriginalURLCtxKey).(url.URL)
 | 
				
			||||||
		return url.QueryEscape(u.Path)
 | 
							return url.QueryEscape(u.Path)
 | 
				
			||||||
 | 
						case "{request_id}":
 | 
				
			||||||
 | 
							reqid, _ := r.request.Context().Value(RequestIDCtxKey).(string)
 | 
				
			||||||
 | 
							return reqid
 | 
				
			||||||
	case "{rewrite_path}":
 | 
						case "{rewrite_path}":
 | 
				
			||||||
		return r.request.URL.Path
 | 
							return r.request.URL.Path
 | 
				
			||||||
	case "{rewrite_path_escaped}":
 | 
						case "{rewrite_path_escaped}":
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										34
									
								
								caddyhttp/requestid/requestid.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								caddyhttp/requestid/requestid.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package requestid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
				
			||||||
 | 
						uuid "github.com/nu7hatch/gouuid"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Handler is a middleware handler
 | 
				
			||||||
 | 
					type Handler struct {
 | 
				
			||||||
 | 
						Next httpserver.Handler
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
 | 
				
			||||||
 | 
						reqid := UUID()
 | 
				
			||||||
 | 
						c := context.WithValue(r.Context(), httpserver.RequestIDCtxKey, reqid)
 | 
				
			||||||
 | 
						r = r.WithContext(c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return h.Next.ServeHTTP(w, r)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UUID returns U4 UUID
 | 
				
			||||||
 | 
					func UUID() string {
 | 
				
			||||||
 | 
						u4, err := uuid.NewV4()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("[ERROR] generating request ID: %v", err)
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return u4.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								caddyhttp/requestid/requestid_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								caddyhttp/requestid/requestid_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					package requestid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRequestID(t *testing.T) {
 | 
				
			||||||
 | 
						request, err := http.NewRequest("GET", "http://localhost/", nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal("Could not create HTTP request:", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reqid := UUID()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c := context.WithValue(request.Context(), httpserver.RequestIDCtxKey, reqid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						request = request.WithContext(c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// See caddyhttp/replacer.go
 | 
				
			||||||
 | 
						value, _ := request.Context().Value(httpserver.RequestIDCtxKey).(string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if value == "" {
 | 
				
			||||||
 | 
							t.Fatal("Request ID should not be empty")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if value != reqid {
 | 
				
			||||||
 | 
							t.Fatal("Request ID does not match")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								caddyhttp/requestid/setup.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								caddyhttp/requestid/setup.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					package requestid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/mholt/caddy"
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						caddy.RegisterPlugin("requestid", caddy.Plugin{
 | 
				
			||||||
 | 
							ServerType: "http",
 | 
				
			||||||
 | 
							Action:     setup,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setup(c *caddy.Controller) error {
 | 
				
			||||||
 | 
						for c.Next() {
 | 
				
			||||||
 | 
							if c.NextArg() {
 | 
				
			||||||
 | 
								return c.ArgErr() //no arg expected.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
 | 
				
			||||||
 | 
							return Handler{Next: next}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								caddyhttp/requestid/setup_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								caddyhttp/requestid/setup_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					package requestid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/mholt/caddy"
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSetup(t *testing.T) {
 | 
				
			||||||
 | 
						c := caddy.NewTestController("http", `requestid`)
 | 
				
			||||||
 | 
						err := setup(c)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected no errors, got: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mids := httpserver.GetConfig(c).Middleware()
 | 
				
			||||||
 | 
						if len(mids) == 0 {
 | 
				
			||||||
 | 
							t.Fatal("Expected middleware, got 0 instead")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handler := mids[0](httpserver.EmptyNext)
 | 
				
			||||||
 | 
						myHandler, ok := handler.(Handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							t.Fatalf("Expected handler to be type Handler, got: %#v", handler)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !httpserver.SameNext(myHandler.Next, httpserver.EmptyNext) {
 | 
				
			||||||
 | 
							t.Error("'Next' field of handler was not set properly")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSetupWithArg(t *testing.T) {
 | 
				
			||||||
 | 
						c := caddy.NewTestController("http", `requestid abc`)
 | 
				
			||||||
 | 
						err := setup(c)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected an error, got: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mids := httpserver.GetConfig(c).Middleware()
 | 
				
			||||||
 | 
						if len(mids) != 0 {
 | 
				
			||||||
 | 
							t.Fatal("Expected no middleware")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								vendor/github.com/nu7hatch/gouuid/COPYING
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/nu7hatch/gouuid/COPYING
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					Copyright (C) 2011 by Krzysztof Kowalik <chris@nu7hat.ch>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
				
			||||||
 | 
					this software and associated documentation files (the "Software"), to deal in
 | 
				
			||||||
 | 
					the Software without restriction, including without limitation the rights to
 | 
				
			||||||
 | 
					use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
				
			||||||
 | 
					of the Software, and to permit persons to whom the Software is furnished to do
 | 
				
			||||||
 | 
					so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE.
 | 
				
			||||||
							
								
								
									
										173
									
								
								vendor/github.com/nu7hatch/gouuid/uuid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								vendor/github.com/nu7hatch/gouuid/uuid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,173 @@
 | 
				
			|||||||
 | 
					// This package provides immutable UUID structs and the functions
 | 
				
			||||||
 | 
					// NewV3, NewV4, NewV5 and Parse() for generating versions 3, 4
 | 
				
			||||||
 | 
					// and 5 UUIDs as specified in RFC 4122.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Copyright (C) 2011 by Krzysztof Kowalik <chris@nu7hat.ch>
 | 
				
			||||||
 | 
					package uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"crypto/md5"
 | 
				
			||||||
 | 
						"crypto/rand"
 | 
				
			||||||
 | 
						"crypto/sha1"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"hash"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The UUID reserved variants. 
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ReservedNCS       byte = 0x80
 | 
				
			||||||
 | 
						ReservedRFC4122   byte = 0x40
 | 
				
			||||||
 | 
						ReservedMicrosoft byte = 0x20
 | 
				
			||||||
 | 
						ReservedFuture    byte = 0x00
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The following standard UUIDs are for use with NewV3() or NewV5().
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						NamespaceDNS, _  = ParseHex("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
 | 
				
			||||||
 | 
						NamespaceURL, _  = ParseHex("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
 | 
				
			||||||
 | 
						NamespaceOID, _  = ParseHex("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
 | 
				
			||||||
 | 
						NamespaceX500, _ = ParseHex("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pattern used to parse hex string representation of the UUID.
 | 
				
			||||||
 | 
					// FIXME: do something to consider both brackets at one time,
 | 
				
			||||||
 | 
					// current one allows to parse string with only one opening
 | 
				
			||||||
 | 
					// or closing bracket.
 | 
				
			||||||
 | 
					const hexPattern = "^(urn\\:uuid\\:)?\\{?([a-z0-9]{8})-([a-z0-9]{4})-" +
 | 
				
			||||||
 | 
						"([1-5][a-z0-9]{3})-([a-z0-9]{4})-([a-z0-9]{12})\\}?$"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var re = regexp.MustCompile(hexPattern)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A UUID representation compliant with specification in
 | 
				
			||||||
 | 
					// RFC 4122 document.
 | 
				
			||||||
 | 
					type UUID [16]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ParseHex creates a UUID object from given hex string
 | 
				
			||||||
 | 
					// representation. Function accepts UUID string in following
 | 
				
			||||||
 | 
					// formats:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     uuid.ParseHex("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
 | 
				
			||||||
 | 
					//     uuid.ParseHex("{6ba7b814-9dad-11d1-80b4-00c04fd430c8}")
 | 
				
			||||||
 | 
					//     uuid.ParseHex("urn:uuid:6ba7b814-9dad-11d1-80b4-00c04fd430c8")
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func ParseHex(s string) (u *UUID, err error) {
 | 
				
			||||||
 | 
						md := re.FindStringSubmatch(s)
 | 
				
			||||||
 | 
						if md == nil {
 | 
				
			||||||
 | 
							err = errors.New("Invalid UUID string")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						hash := md[2] + md[3] + md[4] + md[5] + md[6]
 | 
				
			||||||
 | 
						b, err := hex.DecodeString(hash)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						u = new(UUID)
 | 
				
			||||||
 | 
						copy(u[:], b)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Parse creates a UUID object from given bytes slice.
 | 
				
			||||||
 | 
					func Parse(b []byte) (u *UUID, err error) {
 | 
				
			||||||
 | 
						if len(b) != 16 {
 | 
				
			||||||
 | 
							err = errors.New("Given slice is not valid UUID sequence")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						u = new(UUID)
 | 
				
			||||||
 | 
						copy(u[:], b)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Generate a UUID based on the MD5 hash of a namespace identifier
 | 
				
			||||||
 | 
					// and a name.
 | 
				
			||||||
 | 
					func NewV3(ns *UUID, name []byte) (u *UUID, err error) {
 | 
				
			||||||
 | 
						if ns == nil {
 | 
				
			||||||
 | 
							err = errors.New("Invalid namespace UUID")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						u = new(UUID)
 | 
				
			||||||
 | 
						// Set all bits to MD5 hash generated from namespace and name.
 | 
				
			||||||
 | 
						u.setBytesFromHash(md5.New(), ns[:], name)
 | 
				
			||||||
 | 
						u.setVariant(ReservedRFC4122)
 | 
				
			||||||
 | 
						u.setVersion(3)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Generate a random UUID.
 | 
				
			||||||
 | 
					func NewV4() (u *UUID, err error) {
 | 
				
			||||||
 | 
						u = new(UUID)
 | 
				
			||||||
 | 
						// Set all bits to randomly (or pseudo-randomly) chosen values.
 | 
				
			||||||
 | 
						_, err = rand.Read(u[:])
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						u.setVariant(ReservedRFC4122)
 | 
				
			||||||
 | 
						u.setVersion(4)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Generate a UUID based on the SHA-1 hash of a namespace identifier
 | 
				
			||||||
 | 
					// and a name.
 | 
				
			||||||
 | 
					func NewV5(ns *UUID, name []byte) (u *UUID, err error) {
 | 
				
			||||||
 | 
						u = new(UUID)
 | 
				
			||||||
 | 
						// Set all bits to truncated SHA1 hash generated from namespace
 | 
				
			||||||
 | 
						// and name.
 | 
				
			||||||
 | 
						u.setBytesFromHash(sha1.New(), ns[:], name)
 | 
				
			||||||
 | 
						u.setVariant(ReservedRFC4122)
 | 
				
			||||||
 | 
						u.setVersion(5)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Generate a MD5 hash of a namespace and a name, and copy it to the
 | 
				
			||||||
 | 
					// UUID slice.
 | 
				
			||||||
 | 
					func (u *UUID) setBytesFromHash(hash hash.Hash, ns, name []byte) {
 | 
				
			||||||
 | 
						hash.Write(ns[:])
 | 
				
			||||||
 | 
						hash.Write(name)
 | 
				
			||||||
 | 
						copy(u[:], hash.Sum([]byte{})[:16])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Set the two most significant bits (bits 6 and 7) of the
 | 
				
			||||||
 | 
					// clock_seq_hi_and_reserved to zero and one, respectively.
 | 
				
			||||||
 | 
					func (u *UUID) setVariant(v byte) {
 | 
				
			||||||
 | 
						switch v {
 | 
				
			||||||
 | 
						case ReservedNCS:
 | 
				
			||||||
 | 
							u[8] = (u[8] | ReservedNCS) & 0xBF
 | 
				
			||||||
 | 
						case ReservedRFC4122:
 | 
				
			||||||
 | 
							u[8] = (u[8] | ReservedRFC4122) & 0x7F
 | 
				
			||||||
 | 
						case ReservedMicrosoft:
 | 
				
			||||||
 | 
							u[8] = (u[8] | ReservedMicrosoft) & 0x3F
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Variant returns the UUID Variant, which determines the internal
 | 
				
			||||||
 | 
					// layout of the UUID. This will be one of the constants: RESERVED_NCS,
 | 
				
			||||||
 | 
					// RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE.
 | 
				
			||||||
 | 
					func (u *UUID) Variant() byte {
 | 
				
			||||||
 | 
						if u[8]&ReservedNCS == ReservedNCS {
 | 
				
			||||||
 | 
							return ReservedNCS
 | 
				
			||||||
 | 
						} else if u[8]&ReservedRFC4122 == ReservedRFC4122 {
 | 
				
			||||||
 | 
							return ReservedRFC4122
 | 
				
			||||||
 | 
						} else if u[8]&ReservedMicrosoft == ReservedMicrosoft {
 | 
				
			||||||
 | 
							return ReservedMicrosoft
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ReservedFuture
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Set the four most significant bits (bits 12 through 15) of the
 | 
				
			||||||
 | 
					// time_hi_and_version field to the 4-bit version number.
 | 
				
			||||||
 | 
					func (u *UUID) setVersion(v byte) {
 | 
				
			||||||
 | 
						u[6] = (u[6] & 0xF) | (v << 4)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Version returns a version number of the algorithm used to
 | 
				
			||||||
 | 
					// generate the UUID sequence.
 | 
				
			||||||
 | 
					func (u *UUID) Version() uint {
 | 
				
			||||||
 | 
						return uint(u[6] >> 4)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns unparsed version of the generated UUID sequence.
 | 
				
			||||||
 | 
					func (u *UUID) String() string {
 | 
				
			||||||
 | 
						return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							@ -165,6 +165,14 @@
 | 
				
			|||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"importpath": "github.com/nu7hatch/gouuid",
 | 
				
			||||||
 | 
								"repository": "https://github.com/nu7hatch/gouuid",
 | 
				
			||||||
 | 
								"vcs": "git",
 | 
				
			||||||
 | 
								"revision": "179d4d0c4d8d407a32af483c2354df1d2c91e6c3",
 | 
				
			||||||
 | 
								"branch": "master",
 | 
				
			||||||
 | 
								"notests": true
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"importpath": "github.com/russross/blackfriday",
 | 
								"importpath": "github.com/russross/blackfriday",
 | 
				
			||||||
			"repository": "https://github.com/russross/blackfriday",
 | 
								"repository": "https://github.com/russross/blackfriday",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user