diff options
| author | Adnan Maolood <[email protected]> | 2021-02-23 21:36:29 -0500 |
|---|---|---|
| committer | Adnan Maolood <[email protected]> | 2021-02-23 21:36:29 -0500 |
| commit | f28a63ff0c831e8d29b732a6dedeafbd383f8614 (patch) | |
| tree | 71e330dbe8f09e9bd961dd422ad039717b3fdb96 | |
| parent | ResponseWriter: Add TLS and Conn methods (diff) | |
| download | go-gemini-f28a63ff0c831e8d29b732a6dedeafbd383f8614.tar.xz go-gemini-f28a63ff0c831e8d29b732a6dedeafbd383f8614.zip | |
Add ResponseWriter.Hijack method
| -rw-r--r-- | gemini.go | 7 | ||||
| -rw-r--r-- | response.go | 29 |
2 files changed, 36 insertions, 0 deletions
@@ -20,4 +20,11 @@ var ( // ErrHandlerTimeout is returned on ResponseWriter Write calls // in handlers which have timed out. ErrHandlerTimeout = errors.New("gemini: Handler timeout") + + // ErrHijacked is returned by ResponseWriter.Write calls when + // the underlying connection has been hijacked using the + // Hijacker interface. A zero-byte write on a hijacked + // connection will return ErrHijacked without any other side + // effects. + ErrHijacked = errors.New("gemini: connection has been hijacked") ) diff --git a/response.go b/response.go index 57807e7..12b2354 100644 --- a/response.go +++ b/response.go @@ -126,6 +126,7 @@ type ResponseWriter struct { mediatype string wroteHeader bool bodyAllowed bool + hijacked bool conn net.Conn } @@ -154,6 +155,9 @@ func (w *ResponseWriter) SetMediaType(mediatype string) { // If no media type was set, Write uses a default media type of // "text/gemini; charset=utf-8". func (w *ResponseWriter) Write(b []byte) (int, error) { + if w.hijacked { + return 0, ErrHijacked + } if !w.wroteHeader { meta := w.mediatype if meta == "" { @@ -179,6 +183,9 @@ func (w *ResponseWriter) Write(b []byte) (int, error) { // The provided meta must not be longer than 1024 bytes. // Only one header may be written. func (w *ResponseWriter) WriteHeader(status Status, meta string) { + if w.hijacked { + return + } if w.wroteHeader { return } @@ -196,6 +203,9 @@ func (w *ResponseWriter) WriteHeader(status Status, meta string) { // Flush sends any buffered data to the client. func (w *ResponseWriter) Flush() error { + if w.hijacked { + return ErrHijacked + } if !w.wroteHeader { w.WriteHeader(StatusTemporaryFailure, "Temporary failure") } @@ -206,10 +216,14 @@ func (w *ResponseWriter) Flush() error { // Close closes the connection. // Any blocked Write operations will be unblocked and return errors. func (w *ResponseWriter) Close() error { + if w.hijacked { + return ErrHijacked + } return w.closer.Close() } // Conn returns the underlying network connection. +// To take over the connection, use Hijack. func (w *ResponseWriter) Conn() net.Conn { return w.conn } @@ -222,3 +236,18 @@ func (w *ResponseWriter) TLS() *tls.ConnectionState { } return nil } + +// Hijack lets the caller take over the connection. +// After a call to Hijack the Gemini server library +// will not do anything else with the connection. +// It becomes the caller's responsibility to manage +// and close the connection. +// +// The returned net.Conn may have read or write deadlines +// already set, depending on the configuration of the +// Server. It is the caller's responsibility to set +// or clear those deadlines as needed. +func (w *ResponseWriter) Hijack() net.Conn { + w.hijacked = true + return w.conn +} |