Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WriteControl() changes WriteDeadline permanently #841

Closed
ayjayt opened this issue Jul 20, 2023 · 11 comments
Closed

WriteControl() changes WriteDeadline permanently #841

ayjayt opened this issue Jul 20, 2023 · 11 comments
Labels

Comments

@ayjayt
Copy link

ayjayt commented Jul 20, 2023

I will, later, dig out more information to support this.

https://github.com/gorilla/websocket/blob/9111bb834a68b893cebbbaed5060bdbc1d9ab7d2/conn.go#L463C4-L463C35

func (*Conn) WriteControl
func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error
WriteControl writes a control message with the given deadline. The allowed message types are CloseMessage, PingMessage and PongMessage.

The issue here that the documentation implies that the deadline is set for this one message, whereas it actually calls SetWriteDeadline() and changes the deadline for all subsequent writes as well. It also uses a non-documented default value if supplied time zero &time.Time{} so you should expect this function to change your configuration.

@ghost
Copy link

ghost commented Jul 20, 2023

The network connection's SetWriteDeadline method is called from WriteControl and the internal method used by all other writes. These SetWriteDeadline calls establish the appropriate deadline before the network connection's Write method is called.

A bug this severe seemed unlikely in this popular package. I found the information above by searching for SetWriteDeadline in the code.

@ghost
Copy link

ghost commented Jul 21, 2023

The deadline default value is interesting. It is idiomatic in Go to use a zero time value to specify no deadline. The WriteControl method uses the zero time value to specify a deadline 1000 hours in the future.

There's not a practical difference between no deadline and a deadline 1000 hours in the future, so this is not something that will have an impact on applications.

It is strange.

@ayjayt
Copy link
Author

ayjayt commented Jul 21, 2023

A bug this severe seemed unlikely in this popular package.

The bug isn't that they don't... the bug is that all write calls call SetWriteDeadline in a way that overwrite the user's calls to SetWriteDeadline, but the function descriptions in the docs imply that the write deadline would be set for that single write.

myConn.SetWriteDeadline(myTime)
myConn.WriteControl(websocket.PingMessage, []byte("Hello"), 200 * time.Millisecond) 
// WriteControl is the same as calling SetWriteDeadline, but it's counterintuitive based on docs.

@ayjayt
Copy link
Author

ayjayt commented Jul 21, 2023

The solution is to change the documentation but also accept that accepting a write deadline in the write helper function was unnecessary, let the developer use SetWriteDeadline. Explicit is good.

@ghost
Copy link

ghost commented Jul 21, 2023

The package works as currently documented.

The websocket connection SetWriteDeadline method stores that deadline in a field. The internal write function calls the network connection SetWriteDeadline with the value from the field.

The WriteControl method calls the network connection SetWriteDeadline method before writing to the network connection.

The documented deadline is used in both code paths.

myConn.SetWriteDeadline(myTime) // stores myTime in field
myConn.WriteControl(websocket.PingMessage, []byte("Hello"), 200 * time.Millisecond) // does not change deadline in field
myConn.WriteMessage(...) // uses deadline from field

@ayjayt
Copy link
Author

ayjayt commented Jul 21, 2023

Also, documenting a poor design decision does NOT qualify it as a feature.

@JannikGM
Copy link

JannikGM commented Feb 9, 2024

Why is this tagged as a bug and still open?
The originally documented issue assumes SetWriteDeadline is called on the gorilla websocket object, but it's called on the underlying socket instead, so there is no bug.

This was already explained in:

The other issue about 0 deadline being 1000 hours is weird, but that'd be a separate issue (#895).

@jaitaiwan
Copy link

Thanks for the comment @JannikGM, I'll close this one out, but agree based on the feedback in this thread that the behaviour is unexpected.

@ghost
Copy link

ghost commented Feb 12, 2024

Unexpected? Deadline management works as documented and would be useless if it worked the way OP assumes that it does.

@jaitaiwan
Copy link

I was referring to

0 deadline being 1000 hours

Thanks

@ghost
Copy link

ghost commented Feb 12, 2024

Sorry. Yes, that is weird.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: ✅ Done
Development

No branches or pull requests

4 participants