1 // Copyright (C) MongoDB, Inc. 2017-present. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7 package options // import "go.mongodb.org/mongo-driver/mongo/options" 8 9 import ( 10 "bytes" 11 "context" 12 "crypto/tls" 13 "crypto/x509" 14 "encoding/pem" 15 "errors" 16 "fmt" 17 "io/ioutil" 18 "net" 19 "net/http" 20 "strings" 21 "time" 22 23 "github.com/youmark/pkcs8" 24 "go.mongodb.org/mongo-driver/bson/bsoncodec" 25 "go.mongodb.org/mongo-driver/event" 26 "go.mongodb.org/mongo-driver/internal/httputil" 27 "go.mongodb.org/mongo-driver/mongo/readconcern" 28 "go.mongodb.org/mongo-driver/mongo/readpref" 29 "go.mongodb.org/mongo-driver/mongo/writeconcern" 30 "go.mongodb.org/mongo-driver/tag" 31 "go.mongodb.org/mongo-driver/x/mongo/driver" 32 "go.mongodb.org/mongo-driver/x/mongo/driver/connstring" 33 "go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage" 34 ) 35 36 const ( 37 // ServerMonitoringModeAuto indicates that the client will behave like "poll" 38 // mode when running on a FaaS (Function as a Service) platform, or like 39 // "stream" mode otherwise. The client detects its execution environment by 40 // following the rules for generating the "client.env" handshake metadata field 41 // as specified in the MongoDB Handshake specification. This is the default 42 // mode. 43 ServerMonitoringModeAuto = connstring.ServerMonitoringModeAuto 44 45 // ServerMonitoringModePoll indicates that the client will periodically check 46 // the server using a hello or legacy hello command and then sleep for 47 // heartbeatFrequencyMS milliseconds before running another check. 48 ServerMonitoringModePoll = connstring.ServerMonitoringModePoll 49 50 // ServerMonitoringModeStream indicates that the client will use a streaming 51 // protocol when the server supports it. The streaming protocol optimally 52 // reduces the time it takes for a client to discover server state changes. 53 ServerMonitoringModeStream = connstring.ServerMonitoringModeStream 54 ) 55 56 // ContextDialer is an interface that can be implemented by types that can create connections. It should be used to 57 // provide a custom dialer when configuring a Client. 58 // 59 // DialContext should return a connection to the provided address on the given network. 60 type ContextDialer interface { 61 DialContext(ctx context.Context, network, address string) (net.Conn, error) 62 } 63 64 // Credential can be used to provide authentication options when configuring a Client. 65 // 66 // AuthMechanism: the mechanism to use for authentication. Supported values include "SCRAM-SHA-256", "SCRAM-SHA-1", 67 // "MONGODB-CR", "PLAIN", "GSSAPI", "MONGODB-X509", and "MONGODB-AWS". This can also be set through the "authMechanism" 68 // URI option. (e.g. "authMechanism=PLAIN"). For more information, see 69 // https://www.mongodb.com/docs/manual/core/authentication-mechanisms/. 70 // 71 // AuthMechanismProperties can be used to specify additional configuration options for certain mechanisms. They can also 72 // be set through the "authMechanismProperites" URI option 73 // (e.g. "authMechanismProperties=SERVICE_NAME:service,CANONICALIZE_HOST_NAME:true"). Supported properties are: 74 // 75 // 1. SERVICE_NAME: The service name to use for GSSAPI authentication. The default is "mongodb". 76 // 77 // 2. CANONICALIZE_HOST_NAME: If "true", the driver will canonicalize the host name for GSSAPI authentication. The default 78 // is "false". 79 // 80 // 3. SERVICE_REALM: The service realm for GSSAPI authentication. 81 // 82 // 4. SERVICE_HOST: The host name to use for GSSAPI authentication. This should be specified if the host name to use for 83 // authentication is different than the one given for Client construction. 84 // 85 // 4. AWS_SESSION_TOKEN: The AWS token for MONGODB-AWS authentication. This is optional and used for authentication with 86 // temporary credentials. 87 // 88 // The SERVICE_HOST and CANONICALIZE_HOST_NAME properties must not be used at the same time on Linux and Darwin 89 // systems. 90 // 91 // AuthSource: the name of the database to use for authentication. This defaults to "$external" for MONGODB-X509, 92 // GSSAPI, and PLAIN and "admin" for all other mechanisms. This can also be set through the "authSource" URI option 93 // (e.g. "authSource=otherDb"). 94 // 95 // Username: the username for authentication. This can also be set through the URI as a username:password pair before 96 // the first @ character. For example, a URI for user "user", password "pwd", and host "localhost:27017" would be 97 // "mongodb://user:pwd@localhost:27017". This is optional for X509 authentication and will be extracted from the 98 // client certificate if not specified. 99 // 100 // Password: the password for authentication. This must not be specified for X509 and is optional for GSSAPI 101 // authentication. 102 // 103 // PasswordSet: For GSSAPI, this must be true if a password is specified, even if the password is the empty string, and 104 // false if no password is specified, indicating that the password should be taken from the context of the running 105 // process. For other mechanisms, this field is ignored. 106 type Credential struct { 107 AuthMechanism string 108 AuthMechanismProperties map[string]string 109 AuthSource string 110 Username string 111 Password string 112 PasswordSet bool 113 } 114 115 // BSONOptions are optional BSON marshaling and unmarshaling behaviors. 116 type BSONOptions struct { 117 // UseJSONStructTags causes the driver to fall back to using the "json" 118 // struct tag if a "bson" struct tag is not specified. 119 UseJSONStructTags bool 120 121 // ErrorOnInlineDuplicates causes the driver to return an error if there is 122 // a duplicate field in the marshaled BSON when the "inline" struct tag 123 // option is set. 124 ErrorOnInlineDuplicates bool 125 126 // IntMinSize causes the driver to marshal Go integer values (int, int8, 127 // int16, int32, int64, uint, uint8, uint16, uint32, or uint64) as the 128 // minimum BSON int size (either 32 or 64 bits) that can represent the 129 // integer value. 130 IntMinSize bool 131 132 // NilMapAsEmpty causes the driver to marshal nil Go maps as empty BSON 133 // documents instead of BSON null. 134 // 135 // Empty BSON documents take up slightly more space than BSON null, but 136 // preserve the ability to use document update operations like "$set" that 137 // do not work on BSON null. 138 NilMapAsEmpty bool 139 140 // NilSliceAsEmpty causes the driver to marshal nil Go slices as empty BSON 141 // arrays instead of BSON null. 142 // 143 // Empty BSON arrays take up slightly more space than BSON null, but 144 // preserve the ability to use array update operations like "$push" or 145 // "$addToSet" that do not work on BSON null. 146 NilSliceAsEmpty bool 147 148 // NilByteSliceAsEmpty causes the driver to marshal nil Go byte slices as 149 // empty BSON binary values instead of BSON null. 150 NilByteSliceAsEmpty bool 151 152 // OmitZeroStruct causes the driver to consider the zero value for a struct 153 // (e.g. MyStruct{}) as empty and omit it from the marshaled BSON when the 154 // "omitempty" struct tag option is set. 155 OmitZeroStruct bool 156 157 // StringifyMapKeysWithFmt causes the driver to convert Go map keys to BSON 158 // document field name strings using fmt.Sprint instead of the default 159 // string conversion logic. 160 StringifyMapKeysWithFmt bool 161 162 // AllowTruncatingDoubles causes the driver to truncate the fractional part 163 // of BSON "double" values when attempting to unmarshal them into a Go 164 // integer (int, int8, int16, int32, or int64) struct field. The truncation 165 // logic does not apply to BSON "decimal128" values. 166 AllowTruncatingDoubles bool 167 168 // BinaryAsSlice causes the driver to unmarshal BSON binary field values 169 // that are the "Generic" or "Old" BSON binary subtype as a Go byte slice 170 // instead of a primitive.Binary. 171 BinaryAsSlice bool 172 173 // DefaultDocumentD causes the driver to always unmarshal documents into the 174 // primitive.D type. This behavior is restricted to data typed as 175 // "interface{}" or "map[string]interface{}". 176 DefaultDocumentD bool 177 178 // DefaultDocumentM causes the driver to always unmarshal documents into the 179 // primitive.M type. This behavior is restricted to data typed as 180 // "interface{}" or "map[string]interface{}". 181 DefaultDocumentM bool 182 183 // UseLocalTimeZone causes the driver to unmarshal time.Time values in the 184 // local timezone instead of the UTC timezone. 185 UseLocalTimeZone bool 186 187 // ZeroMaps causes the driver to delete any existing values from Go maps in 188 // the destination value before unmarshaling BSON documents into them. 189 ZeroMaps bool 190 191 // ZeroStructs causes the driver to delete any existing values from Go 192 // structs in the destination value before unmarshaling BSON documents into 193 // them. 194 ZeroStructs bool 195 } 196 197 // ClientOptions contains options to configure a Client instance. Each option can be set through setter functions. See 198 // documentation for each setter function for an explanation of the option. 199 type ClientOptions struct { 200 AppName *string 201 Auth *Credential 202 AutoEncryptionOptions *AutoEncryptionOptions 203 ConnectTimeout *time.Duration 204 Compressors []string 205 Dialer ContextDialer 206 Direct *bool 207 DisableOCSPEndpointCheck *bool 208 HeartbeatInterval *time.Duration 209 Hosts []string 210 HTTPClient *http.Client 211 LoadBalanced *bool 212 LocalThreshold *time.Duration 213 LoggerOptions *LoggerOptions 214 MaxConnIdleTime *time.Duration 215 MaxPoolSize *uint64 216 MinPoolSize *uint64 217 MaxConnecting *uint64 218 PoolMonitor *event.PoolMonitor 219 Monitor *event.CommandMonitor 220 ServerMonitor *event.ServerMonitor 221 ReadConcern *readconcern.ReadConcern 222 ReadPreference *readpref.ReadPref 223 BSONOptions *BSONOptions 224 Registry *bsoncodec.Registry 225 ReplicaSet *string 226 RetryReads *bool 227 RetryWrites *bool 228 ServerAPIOptions *ServerAPIOptions 229 ServerMonitoringMode *string 230 ServerSelectionTimeout *time.Duration 231 SRVMaxHosts *int 232 SRVServiceName *string 233 Timeout *time.Duration 234 TLSConfig *tls.Config 235 WriteConcern *writeconcern.WriteConcern 236 ZlibLevel *int 237 ZstdLevel *int 238 239 err error 240 cs *connstring.ConnString 241 242 // AuthenticateToAnything skips server type checks when deciding if authentication is possible. 243 // 244 // Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any 245 // release. 246 AuthenticateToAnything *bool 247 248 // Crypt specifies a custom driver.Crypt to be used to encrypt and decrypt documents. The default is no 249 // encryption. 250 // 251 // Deprecated: This option is for internal use only and should not be set (see GODRIVER-2149). It may be 252 // changed or removed in any release. 253 Crypt driver.Crypt 254 255 // Deployment specifies a custom deployment to use for the new Client. 256 // 257 // Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any 258 // release. 259 Deployment driver.Deployment 260 261 // SocketTimeout specifies the timeout to be used for the Client's socket reads and writes. 262 // 263 // NOTE(benjirewis): SocketTimeout will be deprecated in a future release. The more general Timeout option 264 // may be used in its place to control the amount of time that a single operation can run before returning 265 // an error. Setting SocketTimeout and Timeout on a single client will result in undefined behavior. 266 SocketTimeout *time.Duration 267 } 268 269 // Client creates a new ClientOptions instance. 270 func Client() *ClientOptions { 271 return &ClientOptions{ 272 HTTPClient: httputil.DefaultHTTPClient, 273 } 274 } 275 276 // Validate validates the client options. This method will return the first error found. 277 func (c *ClientOptions) Validate() error { 278 if c.err != nil { 279 return c.err 280 } 281 c.err = c.validate() 282 return c.err 283 } 284 285 func (c *ClientOptions) validate() error { 286 // Direct connections cannot be made if multiple hosts are specified or an SRV URI is used. 287 if c.Direct != nil && *c.Direct { 288 if len(c.Hosts) > 1 { 289 return errors.New("a direct connection cannot be made if multiple hosts are specified") 290 } 291 if c.cs != nil && c.cs.Scheme == connstring.SchemeMongoDBSRV { 292 return errors.New("a direct connection cannot be made if an SRV URI is used") 293 } 294 } 295 296 if c.MaxPoolSize != nil && c.MinPoolSize != nil && *c.MaxPoolSize != 0 && *c.MinPoolSize > *c.MaxPoolSize { 297 return fmt.Errorf("minPoolSize must be less than or equal to maxPoolSize, got minPoolSize=%d maxPoolSize=%d", *c.MinPoolSize, *c.MaxPoolSize) 298 } 299 300 // verify server API version if ServerAPIOptions are passed in. 301 if c.ServerAPIOptions != nil { 302 if err := c.ServerAPIOptions.ServerAPIVersion.Validate(); err != nil { 303 return err 304 } 305 } 306 307 // Validation for load-balanced mode. 308 if c.LoadBalanced != nil && *c.LoadBalanced { 309 if len(c.Hosts) > 1 { 310 return connstring.ErrLoadBalancedWithMultipleHosts 311 } 312 if c.ReplicaSet != nil { 313 return connstring.ErrLoadBalancedWithReplicaSet 314 } 315 if c.Direct != nil && *c.Direct { 316 return connstring.ErrLoadBalancedWithDirectConnection 317 } 318 } 319 320 // Validation for srvMaxHosts. 321 if c.SRVMaxHosts != nil && *c.SRVMaxHosts > 0 { 322 if c.ReplicaSet != nil { 323 return connstring.ErrSRVMaxHostsWithReplicaSet 324 } 325 if c.LoadBalanced != nil && *c.LoadBalanced { 326 return connstring.ErrSRVMaxHostsWithLoadBalanced 327 } 328 } 329 330 if mode := c.ServerMonitoringMode; mode != nil && !connstring.IsValidServerMonitoringMode(*mode) { 331 return fmt.Errorf("invalid server monitoring mode: %q", *mode) 332 } 333 334 return nil 335 } 336 337 // GetURI returns the original URI used to configure the ClientOptions instance. If ApplyURI was not called during 338 // construction, this returns "". 339 func (c *ClientOptions) GetURI() string { 340 if c.cs == nil { 341 return "" 342 } 343 return c.cs.Original 344 } 345 346 // ApplyURI parses the given URI and sets options accordingly. The URI can contain host names, IPv4/IPv6 literals, or 347 // an SRV record that will be resolved when the Client is created. When using an SRV record, TLS support is 348 // implicitly enabled. Specify the "tls=false" URI option to override this. 349 // 350 // If the connection string contains any options that have previously been set, it will overwrite them. Options that 351 // correspond to multiple URI parameters, such as WriteConcern, will be completely overwritten if any of the query 352 // parameters are specified. If an option is set on ClientOptions after this method is called, that option will override 353 // any option applied via the connection string. 354 // 355 // If the URI format is incorrect or there are conflicting options specified in the URI an error will be recorded and 356 // can be retrieved by calling Validate. 357 // 358 // For more information about the URI format, see https://www.mongodb.com/docs/manual/reference/connection-string/. See 359 // mongo.Connect documentation for examples of using URIs for different Client configurations. 360 func (c *ClientOptions) ApplyURI(uri string) *ClientOptions { 361 if c.err != nil { 362 return c 363 } 364 365 cs, err := connstring.ParseAndValidate(uri) 366 if err != nil { 367 c.err = err 368 return c 369 } 370 c.cs = cs 371 372 if cs.AppName != "" { 373 c.AppName = &cs.AppName 374 } 375 376 // Only create a Credential if there is a request for authentication via non-empty credentials in the URI. 377 if cs.HasAuthParameters() { 378 c.Auth = &Credential{ 379 AuthMechanism: cs.AuthMechanism, 380 AuthMechanismProperties: cs.AuthMechanismProperties, 381 AuthSource: cs.AuthSource, 382 Username: cs.Username, 383 Password: cs.Password, 384 PasswordSet: cs.PasswordSet, 385 } 386 } 387 388 if cs.ConnectSet { 389 direct := cs.Connect == connstring.SingleConnect 390 c.Direct = &direct 391 } 392 393 if cs.DirectConnectionSet { 394 c.Direct = &cs.DirectConnection 395 } 396 397 if cs.ConnectTimeoutSet { 398 c.ConnectTimeout = &cs.ConnectTimeout 399 } 400 401 if len(cs.Compressors) > 0 { 402 c.Compressors = cs.Compressors 403 if stringSliceContains(c.Compressors, "zlib") { 404 defaultLevel := wiremessage.DefaultZlibLevel 405 c.ZlibLevel = &defaultLevel 406 } 407 if stringSliceContains(c.Compressors, "zstd") { 408 defaultLevel := wiremessage.DefaultZstdLevel 409 c.ZstdLevel = &defaultLevel 410 } 411 } 412 413 if cs.HeartbeatIntervalSet { 414 c.HeartbeatInterval = &cs.HeartbeatInterval 415 } 416 417 c.Hosts = cs.Hosts 418 419 if cs.LoadBalancedSet { 420 c.LoadBalanced = &cs.LoadBalanced 421 } 422 423 if cs.LocalThresholdSet { 424 c.LocalThreshold = &cs.LocalThreshold 425 } 426 427 if cs.MaxConnIdleTimeSet { 428 c.MaxConnIdleTime = &cs.MaxConnIdleTime 429 } 430 431 if cs.MaxPoolSizeSet { 432 c.MaxPoolSize = &cs.MaxPoolSize 433 } 434 435 if cs.MinPoolSizeSet { 436 c.MinPoolSize = &cs.MinPoolSize 437 } 438 439 if cs.MaxConnectingSet { 440 c.MaxConnecting = &cs.MaxConnecting 441 } 442 443 if cs.ReadConcernLevel != "" { 444 c.ReadConcern = readconcern.New(readconcern.Level(cs.ReadConcernLevel)) 445 } 446 447 if cs.ReadPreference != "" || len(cs.ReadPreferenceTagSets) > 0 || cs.MaxStalenessSet { 448 opts := make([]readpref.Option, 0, 1) 449 450 tagSets := tag.NewTagSetsFromMaps(cs.ReadPreferenceTagSets) 451 if len(tagSets) > 0 { 452 opts = append(opts, readpref.WithTagSets(tagSets...)) 453 } 454 455 if cs.MaxStaleness != 0 { 456 opts = append(opts, readpref.WithMaxStaleness(cs.MaxStaleness)) 457 } 458 459 mode, err := readpref.ModeFromString(cs.ReadPreference) 460 if err != nil { 461 c.err = err 462 return c 463 } 464 465 c.ReadPreference, c.err = readpref.New(mode, opts...) 466 if c.err != nil { 467 return c 468 } 469 } 470 471 if cs.RetryWritesSet { 472 c.RetryWrites = &cs.RetryWrites 473 } 474 475 if cs.RetryReadsSet { 476 c.RetryReads = &cs.RetryReads 477 } 478 479 if cs.ReplicaSet != "" { 480 c.ReplicaSet = &cs.ReplicaSet 481 } 482 483 if cs.ServerSelectionTimeoutSet { 484 c.ServerSelectionTimeout = &cs.ServerSelectionTimeout 485 } 486 487 if cs.SocketTimeoutSet { 488 c.SocketTimeout = &cs.SocketTimeout 489 } 490 491 if cs.SRVMaxHosts != 0 { 492 c.SRVMaxHosts = &cs.SRVMaxHosts 493 } 494 495 if cs.SRVServiceName != "" { 496 c.SRVServiceName = &cs.SRVServiceName 497 } 498 499 if cs.SSL { 500 tlsConfig := new(tls.Config) 501 502 if cs.SSLCaFileSet { 503 c.err = addCACertFromFile(tlsConfig, cs.SSLCaFile) 504 if c.err != nil { 505 return c 506 } 507 } 508 509 if cs.SSLInsecure { 510 tlsConfig.InsecureSkipVerify = true 511 } 512 513 var x509Subject string 514 var keyPasswd string 515 if cs.SSLClientCertificateKeyPasswordSet && cs.SSLClientCertificateKeyPassword != nil { 516 keyPasswd = cs.SSLClientCertificateKeyPassword() 517 } 518 if cs.SSLClientCertificateKeyFileSet { 519 x509Subject, err = addClientCertFromConcatenatedFile(tlsConfig, cs.SSLClientCertificateKeyFile, keyPasswd) 520 } else if cs.SSLCertificateFileSet || cs.SSLPrivateKeyFileSet { 521 x509Subject, err = addClientCertFromSeparateFiles(tlsConfig, cs.SSLCertificateFile, 522 cs.SSLPrivateKeyFile, keyPasswd) 523 } 524 if err != nil { 525 c.err = err 526 return c 527 } 528 529 // If a username wasn't specified fork x509, add one from the certificate. 530 if c.Auth != nil && strings.ToLower(c.Auth.AuthMechanism) == "mongodb-x509" && 531 c.Auth.Username == "" { 532 533 // The Go x509 package gives the subject with the pairs in reverse order that we want. 534 c.Auth.Username = extractX509UsernameFromSubject(x509Subject) 535 } 536 537 c.TLSConfig = tlsConfig 538 } 539 540 if cs.JSet || cs.WString != "" || cs.WNumberSet || cs.WTimeoutSet { 541 opts := make([]writeconcern.Option, 0, 1) 542 543 if len(cs.WString) > 0 { 544 opts = append(opts, writeconcern.WTagSet(cs.WString)) 545 } else if cs.WNumberSet { 546 opts = append(opts, writeconcern.W(cs.WNumber)) 547 } 548 549 if cs.JSet { 550 opts = append(opts, writeconcern.J(cs.J)) 551 } 552 553 if cs.WTimeoutSet { 554 opts = append(opts, writeconcern.WTimeout(cs.WTimeout)) 555 } 556 557 c.WriteConcern = writeconcern.New(opts...) 558 } 559 560 if cs.ZlibLevelSet { 561 c.ZlibLevel = &cs.ZlibLevel 562 } 563 if cs.ZstdLevelSet { 564 c.ZstdLevel = &cs.ZstdLevel 565 } 566 567 if cs.SSLDisableOCSPEndpointCheckSet { 568 c.DisableOCSPEndpointCheck = &cs.SSLDisableOCSPEndpointCheck 569 } 570 571 if cs.TimeoutSet { 572 c.Timeout = &cs.Timeout 573 } 574 575 return c 576 } 577 578 // SetAppName specifies an application name that is sent to the server when creating new connections. It is used by the 579 // server to log connection and profiling information (e.g. slow query logs). This can also be set through the "appName" 580 // URI option (e.g "appName=example_application"). The default is empty, meaning no app name will be sent. 581 func (c *ClientOptions) SetAppName(s string) *ClientOptions { 582 c.AppName = &s 583 return c 584 } 585 586 // SetAuth specifies a Credential containing options for configuring authentication. See the options.Credential 587 // documentation for more information about Credential fields. The default is an empty Credential, meaning no 588 // authentication will be configured. 589 func (c *ClientOptions) SetAuth(auth Credential) *ClientOptions { 590 c.Auth = &auth 591 return c 592 } 593 594 // SetCompressors sets the compressors that can be used when communicating with a server. Valid values are: 595 // 596 // 1. "snappy" - requires server version >= 3.4 597 // 598 // 2. "zlib" - requires server version >= 3.6 599 // 600 // 3. "zstd" - requires server version >= 4.2, and driver version >= 1.2.0 with cgo support enabled or driver 601 // version >= 1.3.0 without cgo. 602 // 603 // If this option is specified, the driver will perform a negotiation with the server to determine a common list of 604 // compressors and will use the first one in that list when performing operations. See 605 // https://www.mongodb.com/docs/manual/reference/program/mongod/#cmdoption-mongod-networkmessagecompressors for more 606 // information about configuring compression on the server and the server-side defaults. 607 // 608 // This can also be set through the "compressors" URI option (e.g. "compressors=zstd,zlib,snappy"). The default is 609 // an empty slice, meaning no compression will be enabled. 610 func (c *ClientOptions) SetCompressors(comps []string) *ClientOptions { 611 c.Compressors = comps 612 613 return c 614 } 615 616 // SetConnectTimeout specifies a timeout that is used for creating connections to the server. This can be set through 617 // ApplyURI with the "connectTimeoutMS" (e.g "connectTimeoutMS=30") option. If set to 0, no timeout will be used. The 618 // default is 30 seconds. 619 func (c *ClientOptions) SetConnectTimeout(d time.Duration) *ClientOptions { 620 c.ConnectTimeout = &d 621 return c 622 } 623 624 // SetDialer specifies a custom ContextDialer to be used to create new connections to the server. This method overrides 625 // the default net.Dialer, so dialer options such as Timeout, KeepAlive, Resolver, etc can be set. 626 // See https://golang.org/pkg/net/#Dialer for more information about the net.Dialer type. 627 func (c *ClientOptions) SetDialer(d ContextDialer) *ClientOptions { 628 c.Dialer = d 629 return c 630 } 631 632 // SetDirect specifies whether or not a direct connect should be made. If set to true, the driver will only connect to 633 // the host provided in the URI and will not discover other hosts in the cluster. This can also be set through the 634 // "directConnection" URI option. This option cannot be set to true if multiple hosts are specified, either through 635 // ApplyURI or SetHosts, or an SRV URI is used. 636 // 637 // As of driver version 1.4, the "connect" URI option has been deprecated and replaced with "directConnection". The 638 // "connect" URI option has two values: 639 // 640 // 1. "connect=direct" for direct connections. This corresponds to "directConnection=true". 641 // 642 // 2. "connect=automatic" for automatic discovery. This corresponds to "directConnection=false" 643 // 644 // If the "connect" and "directConnection" URI options are both specified in the connection string, their values must 645 // not conflict. Direct connections are not valid if multiple hosts are specified or an SRV URI is used. The default 646 // value for this option is false. 647 func (c *ClientOptions) SetDirect(b bool) *ClientOptions { 648 c.Direct = &b 649 return c 650 } 651 652 // SetHeartbeatInterval specifies the amount of time to wait between periodic background server checks. This can also be 653 // set through the "heartbeatIntervalMS" URI option (e.g. "heartbeatIntervalMS=10000"). The default is 10 seconds. 654 func (c *ClientOptions) SetHeartbeatInterval(d time.Duration) *ClientOptions { 655 c.HeartbeatInterval = &d 656 return c 657 } 658 659 // SetHosts specifies a list of host names or IP addresses for servers in a cluster. Both IPv4 and IPv6 addresses are 660 // supported. IPv6 literals must be enclosed in '[]' following RFC-2732 syntax. 661 // 662 // Hosts can also be specified as a comma-separated list in a URI. For example, to include "localhost:27017" and 663 // "localhost:27018", a URI could be "mongodb://localhost:27017,localhost:27018". The default is ["localhost:27017"] 664 func (c *ClientOptions) SetHosts(s []string) *ClientOptions { 665 c.Hosts = s 666 return c 667 } 668 669 // SetLoadBalanced specifies whether or not the MongoDB deployment is hosted behind a load balancer. This can also be 670 // set through the "loadBalanced" URI option. The driver will error during Client configuration if this option is set 671 // to true and one of the following conditions are met: 672 // 673 // 1. Multiple hosts are specified, either via the ApplyURI or SetHosts methods. This includes the case where an SRV 674 // URI is used and the SRV record resolves to multiple hostnames. 675 // 2. A replica set name is specified, either via the URI or the SetReplicaSet method. 676 // 3. The options specify whether or not a direct connection should be made, either via the URI or the SetDirect method. 677 // 678 // The default value is false. 679 func (c *ClientOptions) SetLoadBalanced(lb bool) *ClientOptions { 680 c.LoadBalanced = &lb 681 return c 682 } 683 684 // SetLocalThreshold specifies the width of the 'latency window': when choosing between multiple suitable servers for an 685 // operation, this is the acceptable non-negative delta between shortest and longest average round-trip times. A server 686 // within the latency window is selected randomly. This can also be set through the "localThresholdMS" URI option (e.g. 687 // "localThresholdMS=15000"). The default is 15 milliseconds. 688 func (c *ClientOptions) SetLocalThreshold(d time.Duration) *ClientOptions { 689 c.LocalThreshold = &d 690 return c 691 } 692 693 // SetLoggerOptions specifies a LoggerOptions containing options for 694 // configuring a logger. 695 func (c *ClientOptions) SetLoggerOptions(opts *LoggerOptions) *ClientOptions { 696 c.LoggerOptions = opts 697 698 return c 699 } 700 701 // SetMaxConnIdleTime specifies the maximum amount of time that a connection will remain idle in a connection pool 702 // before it is removed from the pool and closed. This can also be set through the "maxIdleTimeMS" URI option (e.g. 703 // "maxIdleTimeMS=10000"). The default is 0, meaning a connection can remain unused indefinitely. 704 func (c *ClientOptions) SetMaxConnIdleTime(d time.Duration) *ClientOptions { 705 c.MaxConnIdleTime = &d 706 return c 707 } 708 709 // SetMaxPoolSize specifies that maximum number of connections allowed in the driver's connection pool to each server. 710 // Requests to a server will block if this maximum is reached. This can also be set through the "maxPoolSize" URI option 711 // (e.g. "maxPoolSize=100"). If this is 0, maximum connection pool size is not limited. The default is 100. 712 func (c *ClientOptions) SetMaxPoolSize(u uint64) *ClientOptions { 713 c.MaxPoolSize = &u 714 return c 715 } 716 717 // SetMinPoolSize specifies the minimum number of connections allowed in the driver's connection pool to each server. If 718 // this is non-zero, each server's pool will be maintained in the background to ensure that the size does not fall below 719 // the minimum. This can also be set through the "minPoolSize" URI option (e.g. "minPoolSize=100"). The default is 0. 720 func (c *ClientOptions) SetMinPoolSize(u uint64) *ClientOptions { 721 c.MinPoolSize = &u 722 return c 723 } 724 725 // SetMaxConnecting specifies the maximum number of connections a connection pool may establish simultaneously. This can 726 // also be set through the "maxConnecting" URI option (e.g. "maxConnecting=2"). If this is 0, the default is used. The 727 // default is 2. Values greater than 100 are not recommended. 728 func (c *ClientOptions) SetMaxConnecting(u uint64) *ClientOptions { 729 c.MaxConnecting = &u 730 return c 731 } 732 733 // SetPoolMonitor specifies a PoolMonitor to receive connection pool events. See the event.PoolMonitor documentation 734 // for more information about the structure of the monitor and events that can be received. 735 func (c *ClientOptions) SetPoolMonitor(m *event.PoolMonitor) *ClientOptions { 736 c.PoolMonitor = m 737 return c 738 } 739 740 // SetMonitor specifies a CommandMonitor to receive command events. See the event.CommandMonitor documentation for more 741 // information about the structure of the monitor and events that can be received. 742 func (c *ClientOptions) SetMonitor(m *event.CommandMonitor) *ClientOptions { 743 c.Monitor = m 744 return c 745 } 746 747 // SetServerMonitor specifies an SDAM monitor used to monitor SDAM events. 748 func (c *ClientOptions) SetServerMonitor(m *event.ServerMonitor) *ClientOptions { 749 c.ServerMonitor = m 750 return c 751 } 752 753 // SetReadConcern specifies the read concern to use for read operations. A read concern level can also be set through 754 // the "readConcernLevel" URI option (e.g. "readConcernLevel=majority"). The default is nil, meaning the server will use 755 // its configured default. 756 func (c *ClientOptions) SetReadConcern(rc *readconcern.ReadConcern) *ClientOptions { 757 c.ReadConcern = rc 758 759 return c 760 } 761 762 // SetReadPreference specifies the read preference to use for read operations. This can also be set through the 763 // following URI options: 764 // 765 // 1. "readPreference" - Specify the read preference mode (e.g. "readPreference=primary"). 766 // 767 // 2. "readPreferenceTags": Specify one or more read preference tags 768 // (e.g. "readPreferenceTags=region:south,datacenter:A"). 769 // 770 // 3. "maxStalenessSeconds" (or "maxStaleness"): Specify a maximum replication lag for reads from secondaries in a 771 // replica set (e.g. "maxStalenessSeconds=10"). 772 // 773 // The default is readpref.Primary(). See https://www.mongodb.com/docs/manual/core/read-preference/#read-preference for 774 // more information about read preferences. 775 func (c *ClientOptions) SetReadPreference(rp *readpref.ReadPref) *ClientOptions { 776 c.ReadPreference = rp 777 778 return c 779 } 780 781 // SetBSONOptions configures optional BSON marshaling and unmarshaling behavior. 782 func (c *ClientOptions) SetBSONOptions(opts *BSONOptions) *ClientOptions { 783 c.BSONOptions = opts 784 return c 785 } 786 787 // SetRegistry specifies the BSON registry to use for BSON marshalling/unmarshalling operations. The default is 788 // bson.DefaultRegistry. 789 func (c *ClientOptions) SetRegistry(registry *bsoncodec.Registry) *ClientOptions { 790 c.Registry = registry 791 return c 792 } 793 794 // SetReplicaSet specifies the replica set name for the cluster. If specified, the cluster will be treated as a replica 795 // set and the driver will automatically discover all servers in the set, starting with the nodes specified through 796 // ApplyURI or SetHosts. All nodes in the replica set must have the same replica set name, or they will not be 797 // considered as part of the set by the Client. This can also be set through the "replicaSet" URI option (e.g. 798 // "replicaSet=replset"). The default is empty. 799 func (c *ClientOptions) SetReplicaSet(s string) *ClientOptions { 800 c.ReplicaSet = &s 801 return c 802 } 803 804 // SetRetryWrites specifies whether supported write operations should be retried once on certain errors, such as network 805 // errors. 806 // 807 // Supported operations are InsertOne, UpdateOne, ReplaceOne, DeleteOne, FindOneAndDelete, FindOneAndReplace, 808 // FindOneAndDelete, InsertMany, and BulkWrite. Note that BulkWrite requests must not include UpdateManyModel or 809 // DeleteManyModel instances to be considered retryable. Unacknowledged writes will not be retried, even if this option 810 // is set to true. 811 // 812 // This option requires server version >= 3.6 and a replica set or sharded cluster and will be ignored for any other 813 // cluster type. This can also be set through the "retryWrites" URI option (e.g. "retryWrites=true"). The default is 814 // true. 815 func (c *ClientOptions) SetRetryWrites(b bool) *ClientOptions { 816 c.RetryWrites = &b 817 818 return c 819 } 820 821 // SetRetryReads specifies whether supported read operations should be retried once on certain errors, such as network 822 // errors. 823 // 824 // Supported operations are Find, FindOne, Aggregate without a $out stage, Distinct, CountDocuments, 825 // EstimatedDocumentCount, Watch (for Client, Database, and Collection), ListCollections, and ListDatabases. Note that 826 // operations run through RunCommand are not retried. 827 // 828 // This option requires server version >= 3.6 and driver version >= 1.1.0. The default is true. 829 func (c *ClientOptions) SetRetryReads(b bool) *ClientOptions { 830 c.RetryReads = &b 831 return c 832 } 833 834 // SetServerSelectionTimeout specifies how long the driver will wait to find an available, suitable server to execute an 835 // operation. This can also be set through the "serverSelectionTimeoutMS" URI option (e.g. 836 // "serverSelectionTimeoutMS=30000"). The default value is 30 seconds. 837 func (c *ClientOptions) SetServerSelectionTimeout(d time.Duration) *ClientOptions { 838 c.ServerSelectionTimeout = &d 839 return c 840 } 841 842 // SetSocketTimeout specifies how long the driver will wait for a socket read or write to return before returning a 843 // network error. This can also be set through the "socketTimeoutMS" URI option (e.g. "socketTimeoutMS=1000"). The 844 // default value is 0, meaning no timeout is used and socket operations can block indefinitely. 845 // 846 // NOTE(benjirewis): SocketTimeout will be deprecated in a future release. The more general Timeout option may be used 847 // in its place to control the amount of time that a single operation can run before returning an error. Setting 848 // SocketTimeout and Timeout on a single client will result in undefined behavior. 849 func (c *ClientOptions) SetSocketTimeout(d time.Duration) *ClientOptions { 850 c.SocketTimeout = &d 851 return c 852 } 853 854 // SetTimeout specifies the amount of time that a single operation run on this Client can execute before returning an error. 855 // The deadline of any operation run through the Client will be honored above any Timeout set on the Client; Timeout will only 856 // be honored if there is no deadline on the operation Context. Timeout can also be set through the "timeoutMS" URI option 857 // (e.g. "timeoutMS=1000"). The default value is nil, meaning operations do not inherit a timeout from the Client. 858 // 859 // If any Timeout is set (even 0) on the Client, the values of MaxTime on operation options, TransactionOptions.MaxCommitTime and 860 // SessionOptions.DefaultMaxCommitTime will be ignored. Setting Timeout and SocketTimeout or WriteConcern.wTimeout will result 861 // in undefined behavior. 862 // 863 // NOTE(benjirewis): SetTimeout represents unstable, provisional API. The behavior of the driver when a Timeout is specified is 864 // subject to change. 865 func (c *ClientOptions) SetTimeout(d time.Duration) *ClientOptions { 866 c.Timeout = &d 867 return c 868 } 869 870 // SetTLSConfig specifies a tls.Config instance to use use to configure TLS on all connections created to the cluster. 871 // This can also be set through the following URI options: 872 // 873 // 1. "tls" (or "ssl"): Specify if TLS should be used (e.g. "tls=true"). 874 // 875 // 2. Either "tlsCertificateKeyFile" (or "sslClientCertificateKeyFile") or a combination of "tlsCertificateFile" and 876 // "tlsPrivateKeyFile". The "tlsCertificateKeyFile" option specifies a path to the client certificate and private key, 877 // which must be concatenated into one file. The "tlsCertificateFile" and "tlsPrivateKey" combination specifies separate 878 // paths to the client certificate and private key, respectively. Note that if "tlsCertificateKeyFile" is used, the 879 // other two options must not be specified. Only the subject name of the first certificate is honored as the username 880 // for X509 auth in a file with multiple certs. 881 // 882 // 3. "tlsCertificateKeyFilePassword" (or "sslClientCertificateKeyPassword"): Specify the password to decrypt the client 883 // private key file (e.g. "tlsCertificateKeyFilePassword=password"). 884 // 885 // 4. "tlsCaFile" (or "sslCertificateAuthorityFile"): Specify the path to a single or bundle of certificate authorities 886 // to be considered trusted when making a TLS connection (e.g. "tlsCaFile=/path/to/caFile"). 887 // 888 // 5. "tlsInsecure" (or "sslInsecure"): Specifies whether or not certificates and hostnames received from the server 889 // should be validated. If true (e.g. "tlsInsecure=true"), the TLS library will accept any certificate presented by the 890 // server and any host name in that certificate. Note that setting this to true makes TLS susceptible to 891 // man-in-the-middle attacks and should only be done for testing. 892 // 893 // The default is nil, meaning no TLS will be enabled. 894 func (c *ClientOptions) SetTLSConfig(cfg *tls.Config) *ClientOptions { 895 c.TLSConfig = cfg 896 return c 897 } 898 899 // SetHTTPClient specifies the http.Client to be used for any HTTP requests. 900 // 901 // This should only be used to set custom HTTP client configurations. By default, the connection will use an httputil.DefaultHTTPClient. 902 func (c *ClientOptions) SetHTTPClient(client *http.Client) *ClientOptions { 903 c.HTTPClient = client 904 return c 905 } 906 907 // SetWriteConcern specifies the write concern to use to for write operations. This can also be set through the following 908 // URI options: 909 // 910 // 1. "w": Specify the number of nodes in the cluster that must acknowledge write operations before the operation 911 // returns or "majority" to specify that a majority of the nodes must acknowledge writes. This can either be an integer 912 // (e.g. "w=10") or the string "majority" (e.g. "w=majority"). 913 // 914 // 2. "wTimeoutMS": Specify how long write operations should wait for the correct number of nodes to acknowledge the 915 // operation (e.g. "wTimeoutMS=1000"). 916 // 917 // 3. "journal": Specifies whether or not write operations should be written to an on-disk journal on the server before 918 // returning (e.g. "journal=true"). 919 // 920 // The default is nil, meaning the server will use its configured default. 921 func (c *ClientOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *ClientOptions { 922 c.WriteConcern = wc 923 924 return c 925 } 926 927 // SetZlibLevel specifies the level for the zlib compressor. This option is ignored if zlib is not specified as a 928 // compressor through ApplyURI or SetCompressors. Supported values are -1 through 9, inclusive. -1 tells the zlib 929 // library to use its default, 0 means no compression, 1 means best speed, and 9 means best compression. 930 // This can also be set through the "zlibCompressionLevel" URI option (e.g. "zlibCompressionLevel=-1"). Defaults to -1. 931 func (c *ClientOptions) SetZlibLevel(level int) *ClientOptions { 932 c.ZlibLevel = &level 933 934 return c 935 } 936 937 // SetZstdLevel sets the level for the zstd compressor. This option is ignored if zstd is not specified as a compressor 938 // through ApplyURI or SetCompressors. Supported values are 1 through 20, inclusive. 1 means best speed and 20 means 939 // best compression. This can also be set through the "zstdCompressionLevel" URI option. Defaults to 6. 940 func (c *ClientOptions) SetZstdLevel(level int) *ClientOptions { 941 c.ZstdLevel = &level 942 return c 943 } 944 945 // SetAutoEncryptionOptions specifies an AutoEncryptionOptions instance to automatically encrypt and decrypt commands 946 // and their results. See the options.AutoEncryptionOptions documentation for more information about the supported 947 // options. 948 func (c *ClientOptions) SetAutoEncryptionOptions(opts *AutoEncryptionOptions) *ClientOptions { 949 c.AutoEncryptionOptions = opts 950 return c 951 } 952 953 // SetDisableOCSPEndpointCheck specifies whether or not the driver should reach out to OCSP responders to verify the 954 // certificate status for certificates presented by the server that contain a list of OCSP responders. 955 // 956 // If set to true, the driver will verify the status of the certificate using a response stapled by the server, if there 957 // is one, but will not send an HTTP request to any responders if there is no staple. In this case, the driver will 958 // continue the connection even though the certificate status is not known. 959 // 960 // This can also be set through the tlsDisableOCSPEndpointCheck URI option. Both this URI option and tlsInsecure must 961 // not be set at the same time and will error if they are. The default value is false. 962 func (c *ClientOptions) SetDisableOCSPEndpointCheck(disableCheck bool) *ClientOptions { 963 c.DisableOCSPEndpointCheck = &disableCheck 964 return c 965 } 966 967 // SetServerAPIOptions specifies a ServerAPIOptions instance used to configure the API version sent to the server 968 // when running commands. See the options.ServerAPIOptions documentation for more information about the supported 969 // options. 970 func (c *ClientOptions) SetServerAPIOptions(opts *ServerAPIOptions) *ClientOptions { 971 c.ServerAPIOptions = opts 972 return c 973 } 974 975 // SetServerMonitoringMode specifies the server monitoring protocol to use. See 976 // the helper constants ServerMonitoringModeAuto, ServerMonitoringModePoll, and 977 // ServerMonitoringModeStream for more information about valid server 978 // monitoring modes. 979 func (c *ClientOptions) SetServerMonitoringMode(mode string) *ClientOptions { 980 c.ServerMonitoringMode = &mode 981 982 return c 983 } 984 985 // SetSRVMaxHosts specifies the maximum number of SRV results to randomly select during polling. To limit the number 986 // of hosts selected in SRV discovery, this function must be called before ApplyURI. This can also be set through 987 // the "srvMaxHosts" URI option. 988 func (c *ClientOptions) SetSRVMaxHosts(srvMaxHosts int) *ClientOptions { 989 c.SRVMaxHosts = &srvMaxHosts 990 return c 991 } 992 993 // SetSRVServiceName specifies a custom SRV service name to use in SRV polling. To use a custom SRV service name 994 // in SRV discovery, this function must be called before ApplyURI. This can also be set through the "srvServiceName" 995 // URI option. 996 func (c *ClientOptions) SetSRVServiceName(srvName string) *ClientOptions { 997 c.SRVServiceName = &srvName 998 return c 999 } 1000 1001 // MergeClientOptions combines the given *ClientOptions into a single *ClientOptions in a last one wins fashion. 1002 // The specified options are merged with the existing options on the client, with the specified options taking 1003 // precedence. 1004 // 1005 // Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a 1006 // single options struct instead. 1007 func MergeClientOptions(opts ...*ClientOptions) *ClientOptions { 1008 c := Client() 1009 1010 for _, opt := range opts { 1011 if opt == nil { 1012 continue 1013 } 1014 1015 if opt.Dialer != nil { 1016 c.Dialer = opt.Dialer 1017 } 1018 if opt.AppName != nil { 1019 c.AppName = opt.AppName 1020 } 1021 if opt.Auth != nil { 1022 c.Auth = opt.Auth 1023 } 1024 if opt.AuthenticateToAnything != nil { 1025 c.AuthenticateToAnything = opt.AuthenticateToAnything 1026 } 1027 if opt.Compressors != nil { 1028 c.Compressors = opt.Compressors 1029 } 1030 if opt.ConnectTimeout != nil { 1031 c.ConnectTimeout = opt.ConnectTimeout 1032 } 1033 if opt.Crypt != nil { 1034 c.Crypt = opt.Crypt 1035 } 1036 if opt.HeartbeatInterval != nil { 1037 c.HeartbeatInterval = opt.HeartbeatInterval 1038 } 1039 if len(opt.Hosts) > 0 { 1040 c.Hosts = opt.Hosts 1041 } 1042 if opt.HTTPClient != nil { 1043 c.HTTPClient = opt.HTTPClient 1044 } 1045 if opt.LoadBalanced != nil { 1046 c.LoadBalanced = opt.LoadBalanced 1047 } 1048 if opt.LocalThreshold != nil { 1049 c.LocalThreshold = opt.LocalThreshold 1050 } 1051 if opt.MaxConnIdleTime != nil { 1052 c.MaxConnIdleTime = opt.MaxConnIdleTime 1053 } 1054 if opt.MaxPoolSize != nil { 1055 c.MaxPoolSize = opt.MaxPoolSize 1056 } 1057 if opt.MinPoolSize != nil { 1058 c.MinPoolSize = opt.MinPoolSize 1059 } 1060 if opt.MaxConnecting != nil { 1061 c.MaxConnecting = opt.MaxConnecting 1062 } 1063 if opt.PoolMonitor != nil { 1064 c.PoolMonitor = opt.PoolMonitor 1065 } 1066 if opt.Monitor != nil { 1067 c.Monitor = opt.Monitor 1068 } 1069 if opt.ServerAPIOptions != nil { 1070 c.ServerAPIOptions = opt.ServerAPIOptions 1071 } 1072 if opt.ServerMonitor != nil { 1073 c.ServerMonitor = opt.ServerMonitor 1074 } 1075 if opt.ReadConcern != nil { 1076 c.ReadConcern = opt.ReadConcern 1077 } 1078 if opt.ReadPreference != nil { 1079 c.ReadPreference = opt.ReadPreference 1080 } 1081 if opt.BSONOptions != nil { 1082 c.BSONOptions = opt.BSONOptions 1083 } 1084 if opt.Registry != nil { 1085 c.Registry = opt.Registry 1086 } 1087 if opt.ReplicaSet != nil { 1088 c.ReplicaSet = opt.ReplicaSet 1089 } 1090 if opt.RetryWrites != nil { 1091 c.RetryWrites = opt.RetryWrites 1092 } 1093 if opt.RetryReads != nil { 1094 c.RetryReads = opt.RetryReads 1095 } 1096 if opt.ServerSelectionTimeout != nil { 1097 c.ServerSelectionTimeout = opt.ServerSelectionTimeout 1098 } 1099 if opt.Direct != nil { 1100 c.Direct = opt.Direct 1101 } 1102 if opt.SocketTimeout != nil { 1103 c.SocketTimeout = opt.SocketTimeout 1104 } 1105 if opt.SRVMaxHosts != nil { 1106 c.SRVMaxHosts = opt.SRVMaxHosts 1107 } 1108 if opt.SRVServiceName != nil { 1109 c.SRVServiceName = opt.SRVServiceName 1110 } 1111 if opt.Timeout != nil { 1112 c.Timeout = opt.Timeout 1113 } 1114 if opt.TLSConfig != nil { 1115 c.TLSConfig = opt.TLSConfig 1116 } 1117 if opt.WriteConcern != nil { 1118 c.WriteConcern = opt.WriteConcern 1119 } 1120 if opt.ZlibLevel != nil { 1121 c.ZlibLevel = opt.ZlibLevel 1122 } 1123 if opt.ZstdLevel != nil { 1124 c.ZstdLevel = opt.ZstdLevel 1125 } 1126 if opt.AutoEncryptionOptions != nil { 1127 c.AutoEncryptionOptions = opt.AutoEncryptionOptions 1128 } 1129 if opt.Deployment != nil { 1130 c.Deployment = opt.Deployment 1131 } 1132 if opt.DisableOCSPEndpointCheck != nil { 1133 c.DisableOCSPEndpointCheck = opt.DisableOCSPEndpointCheck 1134 } 1135 if opt.err != nil { 1136 c.err = opt.err 1137 } 1138 if opt.cs != nil { 1139 c.cs = opt.cs 1140 } 1141 if opt.LoggerOptions != nil { 1142 c.LoggerOptions = opt.LoggerOptions 1143 } 1144 if opt.ServerMonitoringMode != nil { 1145 c.ServerMonitoringMode = opt.ServerMonitoringMode 1146 } 1147 } 1148 1149 return c 1150 } 1151 1152 // addCACertFromFile adds a root CA certificate to the configuration given a path 1153 // to the containing file. 1154 func addCACertFromFile(cfg *tls.Config, file string) error { 1155 data, err := ioutil.ReadFile(file) 1156 if err != nil { 1157 return err 1158 } 1159 1160 if cfg.RootCAs == nil { 1161 cfg.RootCAs = x509.NewCertPool() 1162 } 1163 if !cfg.RootCAs.AppendCertsFromPEM(data) { 1164 return errors.New("the specified CA file does not contain any valid certificates") 1165 } 1166 1167 return nil 1168 } 1169 1170 func addClientCertFromSeparateFiles(cfg *tls.Config, keyFile, certFile, keyPassword string) (string, error) { 1171 keyData, err := ioutil.ReadFile(keyFile) 1172 if err != nil { 1173 return "", err 1174 } 1175 certData, err := ioutil.ReadFile(certFile) 1176 if err != nil { 1177 return "", err 1178 } 1179 1180 data := make([]byte, 0, len(keyData)+len(certData)+1) 1181 data = append(data, keyData...) 1182 data = append(data, '\n') 1183 data = append(data, certData...) 1184 return addClientCertFromBytes(cfg, data, keyPassword) 1185 } 1186 1187 func addClientCertFromConcatenatedFile(cfg *tls.Config, certKeyFile, keyPassword string) (string, error) { 1188 data, err := ioutil.ReadFile(certKeyFile) 1189 if err != nil { 1190 return "", err 1191 } 1192 1193 return addClientCertFromBytes(cfg, data, keyPassword) 1194 } 1195 1196 // addClientCertFromBytes adds client certificates to the configuration given a path to the 1197 // containing file and returns the subject name in the first certificate. 1198 func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (string, error) { 1199 var currentBlock *pem.Block 1200 var certDecodedBlock []byte 1201 var certBlocks, keyBlocks [][]byte 1202 1203 remaining := data 1204 start := 0 1205 for { 1206 currentBlock, remaining = pem.Decode(remaining) 1207 if currentBlock == nil { 1208 break 1209 } 1210 1211 if currentBlock.Type == "CERTIFICATE" { 1212 certBlock := data[start : len(data)-len(remaining)] 1213 certBlocks = append(certBlocks, certBlock) 1214 // Assign the certDecodedBlock when it is never set, 1215 // so only the first certificate is honored in a file with multiple certs. 1216 if certDecodedBlock == nil { 1217 certDecodedBlock = currentBlock.Bytes 1218 } 1219 start += len(certBlock) 1220 } else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") { 1221 isEncrypted := x509.IsEncryptedPEMBlock(currentBlock) || strings.Contains(currentBlock.Type, "ENCRYPTED PRIVATE KEY") 1222 if isEncrypted { 1223 if keyPasswd == "" { 1224 return "", fmt.Errorf("no password provided to decrypt private key") 1225 } 1226 1227 var keyBytes []byte 1228 var err error 1229 // Process the X.509-encrypted or PKCS-encrypted PEM block. 1230 if x509.IsEncryptedPEMBlock(currentBlock) { 1231 // Only covers encrypted PEM data with a DEK-Info header. 1232 keyBytes, err = x509.DecryptPEMBlock(currentBlock, []byte(keyPasswd)) 1233 if err != nil { 1234 return "", err 1235 } 1236 } else if strings.Contains(currentBlock.Type, "ENCRYPTED") { 1237 // The pkcs8 package only handles the PKCS #5 v2.0 scheme. 1238 decrypted, err := pkcs8.ParsePKCS8PrivateKey(currentBlock.Bytes, []byte(keyPasswd)) 1239 if err != nil { 1240 return "", err 1241 } 1242 keyBytes, err = x509.MarshalPKCS8PrivateKey(decrypted) 1243 if err != nil { 1244 return "", err 1245 } 1246 } 1247 var encoded bytes.Buffer 1248 pem.Encode(&encoded, &pem.Block{Type: currentBlock.Type, Bytes: keyBytes}) 1249 keyBlock := encoded.Bytes() 1250 keyBlocks = append(keyBlocks, keyBlock) 1251 start = len(data) - len(remaining) 1252 } else { 1253 keyBlock := data[start : len(data)-len(remaining)] 1254 keyBlocks = append(keyBlocks, keyBlock) 1255 start += len(keyBlock) 1256 } 1257 } 1258 } 1259 if len(certBlocks) == 0 { 1260 return "", fmt.Errorf("failed to find CERTIFICATE") 1261 } 1262 if len(keyBlocks) == 0 { 1263 return "", fmt.Errorf("failed to find PRIVATE KEY") 1264 } 1265 1266 cert, err := tls.X509KeyPair(bytes.Join(certBlocks, []byte("\n")), bytes.Join(keyBlocks, []byte("\n"))) 1267 if err != nil { 1268 return "", err 1269 } 1270 1271 cfg.Certificates = append(cfg.Certificates, cert) 1272 1273 // The documentation for the tls.X509KeyPair indicates that the Leaf certificate is not 1274 // retained. 1275 crt, err := x509.ParseCertificate(certDecodedBlock) 1276 if err != nil { 1277 return "", err 1278 } 1279 1280 return crt.Subject.String(), nil 1281 } 1282 1283 func stringSliceContains(source []string, target string) bool { 1284 for _, str := range source { 1285 if str == target { 1286 return true 1287 } 1288 } 1289 return false 1290 } 1291 1292 // create a username for x509 authentication from an x509 certificate subject. 1293 func extractX509UsernameFromSubject(subject string) string { 1294 // the Go x509 package gives the subject with the pairs in the reverse order from what we want. 1295 pairs := strings.Split(subject, ",") 1296 for left, right := 0, len(pairs)-1; left < right; left, right = left+1, right-1 { 1297 pairs[left], pairs[right] = pairs[right], pairs[left] 1298 } 1299 1300 return strings.Join(pairs, ",") 1301 } 1302