Thanks for the response Matt. Some examples to explain my use-case better. First of all, it's important to know that the proxy I am working on uses HTTP handler wrapper to provide additional functionality. The retry handler + response writer wrapper look like the following (code examples are simplified):
type retry struct { next *http.Handler } func (retry *Retry) ServeHTTP(rw http.ResponseWriter, r *http.Request) { attempts := 1 for { retryResponseWriter := newRetryResponseWriter(rw, attempts >= retry.attempts, ...) retry.next.ServeHTTP(retryResponseWriter, r.WithContext(newCtx)) if !retryResponseWriter.ShouldRetry() { break } attempts++ log.Debugf("New attempt %d for request: %v", attempts, r.URL) retry.listener.Retried(r, attempts) } } type retryResponseWriter struct { responseWriter http.ResponseWriter attemptsExhausted bool ... } // Only responses that should not be retried // should be written into the original response writer. func (rr *retryResponseWriter) ShouldRetry() bool { return netErrorOccured() && !rr.attemptsExhausted } func (rr *retryResponseWriter) Header() http.Header { if rr.ShouldRetry() { return make(http.Header) } return rr.responseWriter.Header() } func (rr *retryResponseWriter) Write(buf []byte) (int, error) { if rr.ShouldRetry() { return 0, nil } return rr.responseWriter.Write(buf) } func (rr *retryResponseWriter) WriteHeader(code int) { if rr.ShouldRetry() { return } rr.responseWriter.WriteHeader(code) } func (rr *retryResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { return rr.responseWriter.(http.Hijacker).Hijack() } func (rr *retryResponseWriter) CloseNotify() <-chan bool { return rr.responseWriter.(http.CloseNotifier).CloseNotify() } func (rr *retryResponseWriter) Flush() { if flusher, ok := rr.responseWriter.(http.Flusher); ok { flusher.Flush() } -} My problem is now that the retryResponseWriter always implements the interfaces like Flusher or Hijacker. But actually what I want is that it has the same capabilities as the http.ResponseWriter I am wrapping. An idiomatic usage, to my understanding, of a response writer would look like the following: if hijacker, ok := responseWriter.(Hijacker); ok { conn, rw, err := hijacker.Hijack() if err != nil { // error handling, I even saw sometimes panic() used in this cases } // handle connections } So implementing the interface is definitely something different than returning stub values. However, after having a closer look it looks like that it's safe to implement stub methods for Flush() (as a no-op) and CloseNotify() (returning a new closed channel). If that assumption is right I would only have to create two different retryResponseWriter types, one with Hijack and one without and do a type assertion on the http.ResponseWriter to choose which one. I would favor a more generic way in case someone has a better idea, though. On Tuesday, 16 January 2018 16:10:16 UTC+1, matthe...@gmail.com wrote: > > The type switch may not work since these http types are interfaces that > may all be satisfied by the ResponseWriter. Instead of a type switch you > would need to do a type assertion for each possible http interface. > > Matt > > On Tuesday, January 16, 2018 at 9:01:28 AM UTC-6, matthe...@gmail.com > wrote: >> >> Can you provide some example code showing the problem? >> >> I don’t understand why you are wrapping the ResponseWriter. If you need >> to pass along metadata then wrapping makes sense, but why not just pass the >> original interface and do the type switch in each handler? >> >> type RetryResponseWriter struct { >> http.ResponseWriter >> Count uint >> … >> } >> >> func handler1(w http.ResponseWriter, r *http.Request) { >> rrw := w.(RetryResponseWriter) >> switch v := rrw.ResponseWriter.(type) { >> case http.Hijacker: >> … >> case http.Flusher: >> … >> case http.CloseNotifier: >> … >> } >> … >> >> Matt >> >> On Tuesday, January 16, 2018 at 7:53:40 AM UTC-6, Marco Jantke wrote: >>> >>> Hi everyone, >>> >>> I am currently working on a retry middleware for an http proxy. It is >>> wrapping the original response writer and only in case the forwarded >>> request should not be retried, it passes calls to `Write()`, >>> `WriteHeader()` etc directly through to the original response writer. Now I >>> am struggling with the fact, that response writers have different >>> capabilities dependent on their type. Namely they can be `Hijacker`, >>> `Flusher` or `CloseNotifier`. The problem is that my wrapper should have >>> the same capabilities as the wrapped one, but I don't see any other way >>> than creating all different types and using the proper one after doing type >>> assertions on the response writer I am wrapping. Those types would be for >>> example: `ResponseWriterWrapper`, `ResponseWriterWrapperWithFlush`, >>> `ResponseWriterWrapperWithHijack`, >>> `ResponseWriterWrapperWithHijackAndFlush`.... >>> >>> >>> Does anyone have an idea how to approach this problem in a more >>> reasonable fashion? >>> >> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.