diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 757b43923..83ee27d23 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -764,7 +764,9 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm } if pr := resp.PingRequest; pr != nil { - go answerPing(c.logf, c.httpc, pr) + log.Println("Ping Triggered") + CustomPing(pr) + // go answerPing(c.logf, c.httpc, pr) } if resp.KeepAlive { @@ -862,6 +864,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm c.expiry = &nm.Expiry c.mu.Unlock() + log.Println("MAPRESPONSE: ", resp.Node) cb(nm) } if ctx.Err() != nil { @@ -1214,3 +1217,10 @@ func sleepAsRequested(ctx context.Context, logf logger.Logf, timeoutReset chan<- } } } + +// Run the ping suite from this client to another one +// Send the ping results via http to the adminhttp handlers. +func CustomPing(pr *tailcfg.PingRequest) { + log.Println("Custom Ping Triggered") + log.Println(pr) +} diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index e846ac04c..2c2581b23 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -894,7 +894,7 @@ type PingRequest struct { } // According to https://roamresearch.com/#/app/ts-corp/page/4Bn_Famn2 -// Client can stream responses back. +// Client can stream responses back via HTTP // We will add a struct with the proper fields type StreamedPingResult struct { IP netaddr.IP diff --git a/tsweb/jsonhandler.go b/tsweb/jsonhandler.go index e3154cd5e..546f6de6e 100644 --- a/tsweb/jsonhandler.go +++ b/tsweb/jsonhandler.go @@ -91,9 +91,62 @@ func (fn JSONHandlerFunc) ServeHTTPReturn(w http.ResponseWriter, r *http.Request } // TODO() Set this function such that chunk encoding works +// Currently the same thing with chunking headers set. func (fn JSONHandlerFunc) ServeHTTPChunkEncodingReturn(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Connection", "Keep-Alive") w.Header().Set("Transfer-Encoding", "chunked") w.Header().Set("X-Content-Type-Options", "nosniff") - return nil + var resp *response + status, data, err := fn(r) + if err != nil { + if werr, ok := err.(HTTPError); ok { + resp = &response{ + Status: "error", + Error: werr.Msg, + Data: data, + } + // Unwrap the HTTPError here because we are communicating with + // the client in this handler. We don't want the wrapping + // ReturnHandler to do it too. + err = werr.Err + if werr.Msg != "" { + err = fmt.Errorf("%s: %w", werr.Msg, err) + } + // take status from the HTTPError to encourage error handling in one location + if status != 0 && status != werr.Code { + err = fmt.Errorf("[unexpected] non-zero status that does not match HTTPError status, status: %d, HTTPError.code: %d: %w", status, werr.Code, err) + } + status = werr.Code + } else { + status = http.StatusInternalServerError + resp = &response{ + Status: "error", + Error: "internal server error", + } + } + } else if status == 0 { + status = http.StatusInternalServerError + resp = &response{ + Status: "error", + Error: "internal server error", + } + } else if err == nil { + resp = &response{ + Status: "success", + Data: data, + } + } + b, jerr := json.Marshal(resp) + if jerr != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(`{"status":"error","error":"json marshal error"}`)) + if err != nil { + return fmt.Errorf("%w, and then we could not respond: %v", err, jerr) + } + return jerr + } + + w.WriteHeader(status) + w.Write(b) + return err }