...

Source file src/github.com/jarcoal/httpmock/internal/stack_tracer.go

Documentation: github.com/jarcoal/httpmock/internal

     1  package internal
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net/http"
     7  	"runtime"
     8  	"strings"
     9  )
    10  
    11  type StackTracer struct {
    12  	CustomFn func(...interface{})
    13  	Err      error
    14  }
    15  
    16  // Error implements error interface.
    17  func (s StackTracer) Error() string {
    18  	if s.Err == nil {
    19  		return ""
    20  	}
    21  	return s.Err.Error()
    22  }
    23  
    24  // Unwrap implements the interface needed by errors.Unwrap.
    25  func (s StackTracer) Unwrap() error {
    26  	return s.Err
    27  }
    28  
    29  // CheckStackTracer checks for specific error returned by
    30  // NewNotFoundResponder function or Trace Responder method.
    31  func CheckStackTracer(req *http.Request, err error) error {
    32  	if nf, ok := err.(StackTracer); ok {
    33  		if nf.CustomFn != nil {
    34  			pc := make([]uintptr, 128)
    35  			npc := runtime.Callers(2, pc)
    36  			pc = pc[:npc]
    37  
    38  			var mesg bytes.Buffer
    39  			var netHTTPBegin, netHTTPEnd bool
    40  
    41  			// Start recording at first net/http call if any...
    42  			for {
    43  				frames := runtime.CallersFrames(pc)
    44  
    45  				var lastFn string
    46  				for {
    47  					frame, more := frames.Next()
    48  
    49  					if !netHTTPEnd {
    50  						if netHTTPBegin {
    51  							netHTTPEnd = !strings.HasPrefix(frame.Function, "net/http.")
    52  						} else {
    53  							netHTTPBegin = strings.HasPrefix(frame.Function, "net/http.")
    54  						}
    55  					}
    56  
    57  					if netHTTPEnd {
    58  						if lastFn != "" {
    59  							if mesg.Len() == 0 {
    60  								if nf.Err != nil {
    61  									mesg.WriteString(nf.Err.Error())
    62  								} else {
    63  									fmt.Fprintf(&mesg, "%s %s", req.Method, req.URL)
    64  								}
    65  								mesg.WriteString("\nCalled from ")
    66  							} else {
    67  								mesg.WriteString("\n  ")
    68  							}
    69  							fmt.Fprintf(&mesg, "%s()\n    at %s:%d", lastFn, frame.File, frame.Line)
    70  						}
    71  					}
    72  					lastFn = frame.Function
    73  
    74  					if !more {
    75  						break
    76  					}
    77  				}
    78  
    79  				// At least one net/http frame found
    80  				if mesg.Len() > 0 {
    81  					break
    82  				}
    83  				netHTTPEnd = true // retry without looking at net/http frames
    84  			}
    85  
    86  			nf.CustomFn(mesg.String())
    87  		}
    88  		err = nf.Err
    89  	}
    90  	return err
    91  }
    92  

View as plain text