Repository: open-telemetry/opamp-go
Pull request #288 (2024-06-14 04:48:17)

fix(deps): update module github.com/gorilla/websocket to v1.5.3
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [github.com/gorilla/websocket](https://togithub.com/gorilla/websocket) | `v1.5.2` -> `v1.5.3` | [![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fgorilla%2fwebsocket/v1.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fgorilla%2fwebsocket/v1.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fgorilla%2fwebsocket/v1.5.2/v1.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fgorilla%2fwebsocket/v1.5.2/v1.5.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>gorilla/websocket (github.com/gorilla/websocket)</summary>

### [`v1.5.3`](https://togithub.com/gorilla/websocket/releases/tag/v1.5.3)

[Compare Source](https://togithub.com/gorilla/websocket/compare/v1.5.2...v1.5.3)

#### Important change

This reverts the websockets package back to https://github.com/gorilla/websocket/commit/931041c5ee6de24fe9cba1aa16f1a0b910284d6d

#### What's Changed

-   Fixes subprotocol selection (aling with rfc6455) by [@&#8203;KSDaemon](https://togithub.com/KSDaemon) in [https://github.com/gorilla/websocket/pull/823](https://togithub.com/gorilla/websocket/pull/823)
-   Update README.md, replace master to main by [@&#8203;mstmdev](https://togithub.com/mstmdev) in [https://github.com/gorilla/websocket/pull/862](https://togithub.com/gorilla/websocket/pull/862)
-   Use status code constant by [@&#8203;mstmdev](https://togithub.com/mstmdev) in [https://github.com/gorilla/websocket/pull/864](https://togithub.com/gorilla/websocket/pull/864)
-   conn.go: default close handler should not return ErrCloseSent. by [@&#8203;pnx](https://togithub.com/pnx) in [https://github.com/gorilla/websocket/pull/865](https://togithub.com/gorilla/websocket/pull/865)
-   fix: replace ioutil.readfile with os.readfile by [@&#8203;rfyiamcool](https://togithub.com/rfyiamcool) in [https://github.com/gorilla/websocket/pull/868](https://togithub.com/gorilla/websocket/pull/868)
-   fix: add comment for the readBufferSize and writeBufferSize by [@&#8203;rfyiamcool](https://togithub.com/rfyiamcool) in [https://github.com/gorilla/websocket/pull/869](https://togithub.com/gorilla/websocket/pull/869)
-   Remove noisy printf in NextReader() and beginMessage() by [@&#8203;bcreane](https://togithub.com/bcreane) in [https://github.com/gorilla/websocket/pull/878](https://togithub.com/gorilla/websocket/pull/878)
-   docs(echoreadall): fix function echoReadAll comment by [@&#8203;XdpCs](https://togithub.com/XdpCs) in [https://github.com/gorilla/websocket/pull/881](https://togithub.com/gorilla/websocket/pull/881)
-   make tests parallel by [@&#8203;ninedraft](https://togithub.com/ninedraft) in [https://github.com/gorilla/websocket/pull/872](https://togithub.com/gorilla/websocket/pull/872)
-   Upgrader.Upgrade: use http.ResposnseController by [@&#8203;ninedraft](https://togithub.com/ninedraft) in [https://github.com/gorilla/websocket/pull/871](https://togithub.com/gorilla/websocket/pull/871)
-   Do not handle network error in `SetCloseHandler()` by [@&#8203;nak3](https://togithub.com/nak3) in [https://github.com/gorilla/websocket/pull/863](https://togithub.com/gorilla/websocket/pull/863)
-   perf: reduce timer in write_control by [@&#8203;rfyiamcool](https://togithub.com/rfyiamcool) in [https://github.com/gorilla/websocket/pull/879](https://togithub.com/gorilla/websocket/pull/879)
-   fix: lint example code by [@&#8203;rfyiamcool](https://togithub.com/rfyiamcool) in [https://github.com/gorilla/websocket/pull/890](https://togithub.com/gorilla/websocket/pull/890)
-   feat: format message type by [@&#8203;rfyiamcool](https://togithub.com/rfyiamcool) in [https://github.com/gorilla/websocket/pull/889](https://togithub.com/gorilla/websocket/pull/889)
-   Remove hideTempErr to allow downstream users to check for errors like net.ErrClosed by [@&#8203;UnAfraid](https://togithub.com/UnAfraid) in [https://github.com/gorilla/websocket/pull/894](https://togithub.com/gorilla/websocket/pull/894)
-   Do not timeout when WriteControl deadline is zero in [https://github.com/gorilla/websocket/pull/898](https://togithub.com/gorilla/websocket/pull/898)
-   Excludes errchecks linter by [@&#8203;apoorvajagtap](https://togithub.com/apoorvajagtap) in [https://github.com/gorilla/websocket/pull/904](https://togithub.com/gorilla/websocket/pull/904)
-   Return errors instead of printing to logs by [@&#8203;apoorvajagtap](https://togithub.com/apoorvajagtap) in [https://github.com/gorilla/websocket/pull/897](https://togithub.com/gorilla/websocket/pull/897)
-   Revert " Update go version & add verification/testing tools ([#&#8203;840](https://togithub.com/gorilla/websocket/issues/840))" by [@&#8203;apoorvajagtap](https://togithub.com/apoorvajagtap) in [https://github.com/gorilla/websocket/pull/908](https://togithub.com/gorilla/websocket/pull/908)
-   Fixes broken random value generation by [@&#8203;apoorvajagtap](https://togithub.com/apoorvajagtap) in [https://github.com/gorilla/websocket/pull/926](https://togithub.com/gorilla/websocket/pull/926)
-   Reverts back to v1.5.0 by [@&#8203;apoorvajagtap](https://togithub.com/apoorvajagtap) in [https://github.com/gorilla/websocket/pull/929](https://togithub.com/gorilla/websocket/pull/929)

#### New Contributors

-   [@&#8203;KSDaemon](https://togithub.com/KSDaemon) made their first contribution in [https://github.com/gorilla/websocket/pull/823](https://togithub.com/gorilla/websocket/pull/823)
-   [@&#8203;mstmdev](https://togithub.com/mstmdev) made their first contribution in [https://github.com/gorilla/websocket/pull/862](https://togithub.com/gorilla/websocket/pull/862)
-   [@&#8203;pnx](https://togithub.com/pnx) made their first contribution in [https://github.com/gorilla/websocket/pull/865](https://togithub.com/gorilla/websocket/pull/865)
-   [@&#8203;rfyiamcool](https://togithub.com/rfyiamcool) made their first contribution in [https://github.com/gorilla/websocket/pull/868](https://togithub.com/gorilla/websocket/pull/868)
-   [@&#8203;bcreane](https://togithub.com/bcreane) made their first contribution in [https://github.com/gorilla/websocket/pull/878](https://togithub.com/gorilla/websocket/pull/878)
-   [@&#8203;XdpCs](https://togithub.com/XdpCs) made their first contribution in [https://github.com/gorilla/websocket/pull/881](https://togithub.com/gorilla/websocket/pull/881)
-   [@&#8203;ninedraft](https://togithub.com/ninedraft) made their first contribution in [https://github.com/gorilla/websocket/pull/872](https://togithub.com/gorilla/websocket/pull/872)
-   [@&#8203;nak3](https://togithub.com/nak3) made their first contribution in [https://github.com/gorilla/websocket/pull/863](https://togithub.com/gorilla/websocket/pull/863)
-   [@&#8203;UnAfraid](https://togithub.com/UnAfraid) made their first contribution in [https://github.com/gorilla/websocket/pull/894](https://togithub.com/gorilla/websocket/pull/894)
-   [@&#8203;apoorvajagtap](https://togithub.com/apoorvajagtap) made their first contribution in [https://github.com/gorilla/websocket/pull/904](https://togithub.com/gorilla/websocket/pull/904)

**Full Changelog**: https://github.com/gorilla/websocket/compare/v1.5.1...v1.5.3

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View the [repository job log](https://developer.mend.io/github/open-telemetry/opamp-go).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4zOTMuMCIsInVwZGF0ZWRJblZlciI6IjM3LjQzOC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/open-telemetry/opamp-go/pull/288?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 75.96%. Comparing base [(`c64c461`)](https://app.codecov.io/gh/open-telemetry/opamp-go/commit/c64c461f6232ef41d6e8171148c4d07f17fbdd81?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry) to head [(`fc85854`)](https://app.codecov.io/gh/open-telemetry/opamp-go/commit/fc85854885037fa69ad74f3180c3fcf4920f81bc?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry).


<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main     #288   +/-   ##
=======================================
  Coverage   75.96%   75.96%           
=======================================
  Files          25       25           
  Lines        1656     1656           
=======================================
  Hits         1258     1258           
  Misses        291      291           
  Partials      107      107           
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/open-telemetry/opamp-go/pull/288?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-telemetry).


Patch:
diff --git a/client/client.go b/client/client.go
index da9a818..afc0831 100644
--- a/client/client.go
+++ b/client/client.go
@@ -107,6 +107,16 @@ type OpAMPClient interface {
 	// for more details.
 	SetCustomCapabilities(customCapabilities *protobufs.CustomCapabilities) error
 
+	// SetFlags modifies the set of flags supported by the client.
+	// May be called before or after Start(), including from OnMessage handler.
+	// The zero value of protobufs.AgentToServerFlags corresponds to FlagsUnspecified
+	// and is safe to use.
+	//
+	// See
+	// https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#agenttoserverflags
+	// for more details.
+	SetFlags(flags protobufs.AgentToServerFlags)
+
 	// SendCustomMessage sends the custom message to the Server. May be called anytime after
 	// Start(), including from OnMessage handler.
 	//
diff --git a/client/httpclient.go b/client/httpclient.go
index 117c818..b27c249 100644
--- a/client/httpclient.go
+++ b/client/httpclient.go
@@ -105,11 +105,16 @@ func (c *httpClient) SetPackageStatuses(statuses *protobufs.PackageStatuses) err
 	return c.common.SetPackageStatuses(statuses)
 }
 
-// SendCustomMessage implements OpAMPClient.SetCustomCapabilities.
+// SendCustomCapabilities implements OpAMPClient.SetCustomCapabilities.
 func (c *httpClient) SetCustomCapabilities(customCapabilities *protobufs.CustomCapabilities) error {
 	return c.common.SetCustomCapabilities(customCapabilities)
 }
 
+// SetFlags implements OpAMPClient.SetFlags.
+func (c *httpClient) SetFlags(flags protobufs.AgentToServerFlags) {
+	c.common.SetFlags(flags)
+}
+
 // SendCustomMessage implements OpAMPClient.SendCustomMessage.
 func (c *httpClient) SendCustomMessage(message *protobufs.CustomMessage) (messageSendingChannel chan struct{}, err error) {
 	return c.common.SendCustomMessage(message)
diff --git a/client/internal/clientcommon.go b/client/internal/clientcommon.go
index 4521ff9..a8df364 100644
--- a/client/internal/clientcommon.go
+++ b/client/internal/clientcommon.go
@@ -214,6 +214,7 @@ func (c *ClientCommon) PrepareFirstMessage(ctx context.Context) error {
 			msg.PackageStatuses = c.ClientSyncedState.PackageStatuses()
 			msg.Capabilities = uint64(c.Capabilities)
 			msg.CustomCapabilities = c.ClientSyncedState.CustomCapabilities()
+			msg.Flags = c.ClientSyncedState.Flags()
 		},
 	)
 	return nil
@@ -385,6 +386,19 @@ func (c *ClientCommon) SetCustomCapabilities(customCapabilities *protobufs.Custo
 	return nil
 }
 
+func (c *ClientCommon) SetFlags(flags protobufs.AgentToServerFlags) {
+	// store the flags to send
+	c.ClientSyncedState.SetFlags(flags)
+
+	// send the new flags to the Server
+	c.sender.NextMessage().Update(
+		func(msg *protobufs.AgentToServer) {
+			msg.Flags = uint64(flags)
+		},
+	)
+	c.sender.ScheduleSend()
+}
+
 // SendCustomMessage sends the specified custom message to the server.
 func (c *ClientCommon) SendCustomMessage(message *protobufs.CustomMessage) (messageSendingChannel chan struct{}, err error) {
 	if message == nil {
diff --git a/client/internal/clientstate.go b/client/internal/clientstate.go
index 97eb4dc..93250c9 100644
--- a/client/internal/clientstate.go
+++ b/client/internal/clientstate.go
@@ -17,8 +17,8 @@ var (
 )
 
 // ClientSyncedState stores the state of the Agent messages that the OpAMP Client needs to
-// have access to synchronize to the Server. 5 messages can be stored in this store:
-// AgentDescription, ComponentHealth, RemoteConfigStatus, PackageStatuses and CustomCapabilities.
+// have access to synchronize to the Server. Six messages can be stored in this store:
+// AgentDescription, ComponentHealth, RemoteConfigStatus, PackageStatuses, CustomCapabilities and Flags.
 //
 // See OpAMP spec for more details on how status reporting works:
 // https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#status-reporting
@@ -39,6 +39,7 @@ type ClientSyncedState struct {
 	remoteConfigStatus *protobufs.RemoteConfigStatus
 	packageStatuses    *protobufs.PackageStatuses
 	customCapabilities *protobufs.CustomCapabilities
+	flags              protobufs.AgentToServerFlags
 }
 
 func (s *ClientSyncedState) AgentDescription() *protobufs.AgentDescription {
@@ -71,6 +72,12 @@ func (s *ClientSyncedState) CustomCapabilities() *protobufs.CustomCapabilities {
 	return s.customCapabilities
 }
 
+func (s *ClientSyncedState) Flags() uint64 {
+	defer s.mutex.Unlock()
+	s.mutex.Lock()
+	return uint64(s.flags)
+}
+
 // SetAgentDescription sets the AgentDescription in the state.
 func (s *ClientSyncedState) SetAgentDescription(descr *protobufs.AgentDescription) error {
 	if descr == nil {
@@ -168,3 +175,11 @@ func (s *ClientSyncedState) HasCustomCapability(capability string) bool {
 
 	return false
 }
+
+// SetFlags sets the flags in the state.
+func (s *ClientSyncedState) SetFlags(flags protobufs.AgentToServerFlags) {
+	defer s.mutex.Unlock()
+	s.mutex.Lock()
+
+	s.flags = flags
+}
diff --git a/client/internal/receivedprocessor.go b/client/internal/receivedprocessor.go
index 736073d..bd18a14 100644
--- a/client/internal/receivedprocessor.go
+++ b/client/internal/receivedprocessor.go
@@ -190,8 +190,9 @@ func (r *receivedProcessor) rcvFlags(
 				msg.RemoteConfigStatus = r.clientSyncedState.RemoteConfigStatus()
 				msg.PackageStatuses = r.clientSyncedState.PackageStatuses()
 				msg.CustomCapabilities = r.clientSyncedState.CustomCapabilities()
+				msg.Flags = r.clientSyncedState.Flags()
 
-				// The logic for EffectiveConfig is similar to the previous 5 sub-messages however
+				// The logic for EffectiveConfig is similar to the previous 6 sub-messages however
 				// the EffectiveConfig is fetched using GetEffectiveConfig instead of
 				// from clientSyncedState. We do this to avoid keeping EffectiveConfig in-memory.
 				msg.EffectiveConfig = cfg
@@ -237,6 +238,9 @@ func (r *receivedProcessor) rcvAgentIdentification(ctx context.Context, agentId
 		return err
 	}
 
+	// If we set up a new instance ID, reset the RequestInstanceUid flag.
+	r.clientSyncedState.flags &^= protobufs.AgentToServerFlags_AgentToServerFlags_RequestInstanceUid
+
 	return nil
 }
 
diff --git a/client/wsclient.go b/client/wsclient.go
index b017a44..030972f 100644
--- a/client/wsclient.go
+++ b/client/wsclient.go
@@ -129,6 +129,10 @@ func (c *wsClient) SetCustomCapabilities(customCapabilities *protobufs.CustomCap
 	return c.common.SetCustomCapabilities(customCapabilities)
 }
 
+func (c *wsClient) SetFlags(flags protobufs.AgentToServerFlags) {
+	c.common.SetFlags(flags)
+}
+
 func (c *wsClient) SendCustomMessage(message *protobufs.CustomMessage) (messageSendingChannel chan struct{}, err error) {
 	return c.common.SendCustomMessage(message)
 }
diff --git a/go.mod b/go.mod
index 8bb4d4c..963bef1 100644
--- a/go.mod
+++ b/go.mod
@@ -5,16 +5,15 @@ go 1.20
 require (
 	github.com/cenkalti/backoff/v4 v4.3.0
 	github.com/google/uuid v1.6.0
-	github.com/gorilla/websocket v1.5.2
+	github.com/gorilla/websocket v1.5.3
 	github.com/stretchr/testify v1.9.0
-	google.golang.org/protobuf v1.34.1
+	google.golang.org/protobuf v1.34.2
 )
 
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/google/go-cmp v0.5.6 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	golang.org/x/net v0.23.0 // indirect
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index ccac2eb..ee48aec 100644
--- a/go.sum
+++ b/go.sum
@@ -6,19 +6,17 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/websocket v1.5.2 h1:qoW6V1GT3aZxybsbC6oLnailWnB+qTMVwMreOso9XUw=
-github.com/gorilla/websocket v1.5.2/go.mod h1:0n9H61RBAcf5/38py2MCYbxzPIY9rOkpvvMT24Rqs30=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
-golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/internal/examples/go.mod b/internal/examples/go.mod
index d2d9b60..0e87067 100644
--- a/internal/examples/go.mod
+++ b/internal/examples/go.mod
@@ -16,7 +16,7 @@ require (
 	go.opentelemetry.io/otel/metric v1.24.0
 	go.opentelemetry.io/otel/sdk v1.24.0
 	go.opentelemetry.io/otel/sdk/metric v1.24.0
-	google.golang.org/protobuf v1.34.1
+	google.golang.org/protobuf v1.34.2
 )
 
 require (
@@ -27,7 +27,7 @@ require (
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-ole/go-ole v1.2.6 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
-	github.com/gorilla/websocket v1.5.2 // indirect
+	github.com/gorilla/websocket v1.5.3 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
 	github.com/mitchellh/copystructure v1.2.0 // indirect
 	github.com/mitchellh/mapstructure v1.4.1 // indirect
diff --git a/internal/examples/go.sum b/internal/examples/go.sum
index 00bf0ae..3f93d8b 100644
--- a/internal/examples/go.sum
+++ b/internal/examples/go.sum
@@ -49,8 +49,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/websocket v1.5.2 h1:qoW6V1GT3aZxybsbC6oLnailWnB+qTMVwMreOso9XUw=
-github.com/gorilla/websocket v1.5.2/go.mod h1:0n9H61RBAcf5/38py2MCYbxzPIY9rOkpvvMT24Rqs30=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -203,8 +203,8 @@ google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
 google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/internal/retryafter.go b/internal/retryafter.go
index 784473b..593cd2c 100644
--- a/internal/retryafter.go
+++ b/internal/retryafter.go
@@ -18,26 +18,32 @@ type OptionalDuration struct {
 }
 
 func parseDelaySeconds(s string) (time.Duration, error) {
+	// Verify duration parsed properly
 	n, err := strconv.Atoi(s)
+	if err != nil {
+		return 0, errCouldNotParseRetryAfterHeader
+	}
 
-	// Verify duration parsed properly and bigger than 0
-	if err == nil && n > 0 {
+	// If n > 0 return n seconds, otherwise return 0
+	if n > 0 {
 		duration := time.Duration(n) * time.Second
 		return duration, nil
 	}
-	return 0, errCouldNotParseRetryAfterHeader
+	return 0, nil
 }
 
 func parseHTTPDate(s string) (time.Duration, error) {
+	// Verify duration parsed properly
 	t, err := http.ParseTime(s)
+	if err != nil {
+		return 0, errCouldNotParseRetryAfterHeader
+	}
 
-	// Verify duration parsed properly and bigger than 0
-	if err == nil {
-		if duration := time.Until(t); duration > 0 {
-			return duration, nil
-		}
+	// If the date is in the future return that duration, otherwise return 0
+	if duration := time.Until(t); duration > 0 {
+		return duration, nil
 	}
-	return 0, errCouldNotParseRetryAfterHeader
+	return 0, nil
 }
 
 // ExtractRetryAfterHeader extracts Retry-After response header if the status


Test patch:
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 8084406..7592e51 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -13,7 +13,7 @@ jobs:
       - name: Checkout Repo
         uses: actions/checkout@v4
       - name: Setup Go
-        uses: actions/setup-go@v5.0.1
+        uses: actions/setup-go@v5.0.2
         with:
           go-version: "1.20"
       - name: Setup Go Environment
@@ -46,7 +46,7 @@ jobs:
       - name: Checkout Repo
         uses: actions/checkout@v4
       - name: Setup Go
-        uses: actions/setup-go@v5.0.1
+        uses: actions/setup-go@v5.0.2
         with:
           go-version: "1.20"
       - name: Setup Go Environment
diff --git a/client/clientimpl_test.go b/client/clientimpl_test.go
index 46e8510..78ecb5c 100644
--- a/client/clientimpl_test.go
+++ b/client/clientimpl_test.go
@@ -93,7 +93,7 @@ func eventually(t *testing.T, f func() bool) {
 	assert.Eventually(t, f, 5*time.Second, 10*time.Millisecond)
 }
 
-func newInstanceUid(t *testing.T) types.InstanceUid {
+func genNewInstanceUid(t *testing.T) types.InstanceUid {
 	uid, err := uuid.NewV7()
 	require.NoError(t, err)
 	b, err := uid.MarshalBinary()
@@ -103,7 +103,7 @@ func newInstanceUid(t *testing.T) types.InstanceUid {
 
 func prepareSettings(t *testing.T, settings *types.StartSettings, c OpAMPClient) {
 	// Autogenerate instance id.
-	settings.InstanceUid = newInstanceUid(t)
+	settings.InstanceUid = genNewInstanceUid(t)
 
 	// Make sure correct URL scheme is used, based on the type of the OpAMP client.
 	u, err := url.Parse(settings.OpAMPServerURL)
@@ -630,27 +630,24 @@ func TestAgentIdentification(t *testing.T) {
 	testClients(t, func(t *testing.T, client OpAMPClient) {
 		// Start a server.
 		srv := internal.StartMockServer(t)
-		newInstanceUid := newInstanceUid(t)
+		newInstanceUid := genNewInstanceUid(t)
 		var rcvAgentInstanceUid atomic.Value
-		var sentInvalidId atomic.Bool
 		srv.OnMessage = func(msg *protobufs.AgentToServer) *protobufs.ServerToAgent {
-			rcvAgentInstanceUid.Store(msg.InstanceUid)
-			if sentInvalidId.Load() {
+			if msg.Flags&uint64(protobufs.AgentToServerFlags_AgentToServerFlags_RequestInstanceUid) == 1 {
+				newInstanceUid = genNewInstanceUid(t)
+				rcvAgentInstanceUid.Store(newInstanceUid[:])
 				return &protobufs.ServerToAgent{
 					InstanceUid: msg.InstanceUid,
 					AgentIdentification: &protobufs.AgentIdentification{
-						// If we sent the invalid one first, send a valid one now
+						// If the RequestInstanceUid flag was set, populate this field.
 						NewInstanceUid: newInstanceUid[:],
 					},
 				}
 			}
-			sentInvalidId.Store(true)
+			rcvAgentInstanceUid.Store(msg.InstanceUid)
+			// Start by sending just the old instance ID.
 			return &protobufs.ServerToAgent{
 				InstanceUid: msg.InstanceUid,
-				AgentIdentification: &protobufs.AgentIdentification{
-					// Start by sending an invalid id forcing an error.
-					NewInstanceUid: nil,
-				},
 			}
 		}
 
@@ -689,8 +686,8 @@ func TestAgentIdentification(t *testing.T) {
 			},
 		)
 
-		// Send a dummy message again to get the _new_ id
-		_ = client.SetAgentDescription(createAgentDescr())
+		// Set the flags to request a new ID.
+		client.SetFlags(protobufs.AgentToServerFlags_AgentToServerFlags_RequestInstanceUid)
 
 		// When it was sent, the new instance uid should have been used, which should
 		// have been observed by the Server
@@ -2122,3 +2119,104 @@ func TestSetCustomCapabilities(t *testing.T) {
 		assert.NoError(t, err)
 	})
 }
+
+// TestSetFlags tests the ability for the client to change the set of flags it sends.
+func TestSetFlags(t *testing.T) {
+	testClients(t, func(t *testing.T, client OpAMPClient) {
+
+		// Start a Server.
+		srv := internal.StartMockServer(t)
+		var rcvCustomFlags atomic.Value
+		var flags protobufs.AgentToServerFlags
+
+		srv.OnMessage = func(msg *protobufs.AgentToServer) *protobufs.ServerToAgent {
+			if msg.Flags != 0 {
+				rcvCustomFlags.Store(msg.Flags)
+			}
+			return nil
+		}
+
+		settings := types.StartSettings{}
+		settings.OpAMPServerURL = "ws://" + srv.Endpoint
+		prepareClient(t, &settings, client)
+
+		assert.NoError(t, client.Start(context.Background(), settings))
+
+		// The zero value of AgentToServerFlags is ready to use
+		client.SetFlags(flags)
+
+		// Update flags to send
+		flags |= protobufs.AgentToServerFlags_AgentToServerFlags_RequestInstanceUid
+		client.SetFlags(flags)
+
+		// Verify new flags were delivered to the server
+		eventually(
+			t,
+			func() bool {
+				msg, ok := rcvCustomFlags.Load().(uint64)
+				if !ok || msg == 0 {
+					return false
+				}
+				return uint64(flags) == msg
+			},
+		)
+
+		// Shutdown the Server.
+		srv.Close()
+
+		// Shutdown the client.
+		err := client.Stop(context.Background())
+		assert.NoError(t, err)
+	})
+}
+
+// TestSetFlags tests the ability for the client to set its flags before starting up.
+func TestSetFlagsBeforeStart(t *testing.T) {
+	testClients(t, func(t *testing.T, client OpAMPClient) {
+		// Start a Server.
+		flags := protobufs.AgentToServerFlags_AgentToServerFlags_RequestInstanceUid
+		srv := internal.StartMockServer(t)
+		var rcvCustomFlags atomic.Value
+		var isFirstMessage atomic.Bool
+		isFirstMessage.Store(true)
+
+		// Make sure we only record flags from the very first message.
+		srv.OnMessage = func(msg *protobufs.AgentToServer) *protobufs.ServerToAgent {
+			if isFirstMessage.Load() {
+				rcvCustomFlags.Store(msg.Flags)
+			}
+			isFirstMessage.Store(false)
+			return nil
+		}
+
+		settings := types.StartSettings{}
+		settings.OpAMPServerURL = "ws://" + srv.Endpoint
+		prepareClient(t, &settings, client)
+
+		// Set up the flags _before_ calling Start to verify that they're
+		// handled correctly in PrepareFirstMessage.
+		client.SetFlags(flags)
+
+		// Start the client.
+		assert.NoError(t, client.Start(context.Background(), settings))
+
+		// Verify the flags were delivered to the server during the first message.
+		eventually(
+			t,
+			func() bool {
+				msg, ok := rcvCustomFlags.Load().(uint64)
+				if !ok || msg == 0 {
+					return false
+				}
+				return uint64(flags) == msg
+			},
+		)
+
+		// Shutdown the Server.
+		srv.Close()
+
+		// Shutdown the client.
+		err := client.Stop(context.Background())
+		assert.NoError(t, err)
+	})
+}
diff --git a/client/internal/httpsender_test.go b/client/internal/httpsender_test.go
index 420bc9e..65df9c5 100644
--- a/client/internal/httpsender_test.go
+++ b/client/internal/httpsender_test.go
@@ -172,3 +172,39 @@ func TestHTTPSenderRetryForFailedRequests(t *testing.T) {
 	cancel()
 	srv.Close()
 }
+
+func TestRequestInstanceUidFlagReset(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+
+	sender := NewHTTPSender(&sharedinternal.NopLogger{})
+	sender.callbacks = types.CallbacksStruct{}
+
+	// Set the RequestInstanceUid flag on the tracked state to request the server for a new ID to use.
+	clientSyncedState := &ClientSyncedState{}
+	clientSyncedState.SetFlags(protobufs.AgentToServerFlags_AgentToServerFlags_RequestInstanceUid)
+	capabilities := protobufs.AgentCapabilities_AgentCapabilities_Unspecified
+	sender.receiveProcessor = newReceivedProcessor(&sharedinternal.NopLogger{}, sender.callbacks, sender, clientSyncedState, nil, capabilities)
+
+	// If we process a message with a nil AgentIdentification, or an incorrect NewInstanceUid.
+	sender.receiveProcessor.ProcessReceivedMessage(ctx,
+		&protobufs.ServerToAgent{
+			AgentIdentification: nil,
+		})
+	sender.receiveProcessor.ProcessReceivedMessage(ctx,
+		&protobufs.ServerToAgent{
+			AgentIdentification: &protobufs.AgentIdentification{NewInstanceUid: []byte("foo")},
+		})
+
+	// Then the RequestInstanceUid flag stays intact.
+	assert.Equal(t, sender.receiveProcessor.clientSyncedState.flags, protobufs.AgentToServerFlags_AgentToServerFlags_RequestInstanceUid)
+
+	// If we process a message that contains a non-nil AgentIdentification that contains a NewInstanceUid.
+	sender.receiveProcessor.ProcessReceivedMessage(ctx,
+		&protobufs.ServerToAgent{
+			AgentIdentification: &protobufs.AgentIdentification{NewInstanceUid: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
+		})
+
+	// Then the flag is reset so we don't request a new instance uid yet again.
+	assert.Equal(t, sender.receiveProcessor.clientSyncedState.flags, protobufs.AgentToServerFlags_AgentToServerFlags_Unspecified)
+	cancel()
+}
diff --git a/internal/retryafter_test.go b/internal/retryafter_test.go
index f2e36e9..123ada1 100644
--- a/internal/retryafter_test.go
+++ b/internal/retryafter_test.go
@@ -50,9 +50,10 @@ func TestExtractRetryAfterHeaderDelaySeconds(t *testing.T) {
 	resp.StatusCode = http.StatusBadGateway
 	assertUndefinedDuration(t, ExtractRetryAfterHeader(resp))
 
-	// Verify no duration is created for n < 0
+	// Verify a zero duration is created for n < 0
+	resp.StatusCode = http.StatusTooManyRequests
 	resp.Header.Set(retryAfterHTTPHeader, strconv.Itoa(-1))
-	assertUndefinedDuration(t, ExtractRetryAfterHeader(resp))
+	assertDuration(t, ExtractRetryAfterHeader(resp), 0)
 }
 
 func TestExtractRetryAfterHeaderHttpDate(t *testing.T) {
@@ -81,7 +82,11 @@ func TestExtractRetryAfterHeaderHttpDate(t *testing.T) {
 	resp.Header.Set(retryAfterHTTPHeader, retryAfter.Format(time.RFC1123))
 	assertUndefinedDuration(t, ExtractRetryAfterHeader(resp))
 
-	// Verify no duration is created for n < 0
+	// Verify a zero duration is created for n = 0
+	resp.Header.Set(retryAfterHTTPHeader, now.UTC().Format(http.TimeFormat))
+	assertDuration(t, ExtractRetryAfterHeader(resp), 0)
+
+	// Verify a zero duration is created for n < 0
 	resp.Header.Set(retryAfterHTTPHeader, now.Add(-1*time.Second).UTC().Format(http.TimeFormat))
-	assertUndefinedDuration(t, ExtractRetryAfterHeader(resp))
+	assertDuration(t, ExtractRetryAfterHeader(resp), 0)
 }