// logStackOnRecover is the default RecoverHandleFunction and is called // when DoNotRecover is false and the recoverHandleFunc is not set for the container. // Default implementation logs the stacktrace and writes the stacktrace on the response. // This may be a security issue as it exposes sourcecode information. func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter) { var buffer bytes.Buffer buffer.WriteString(fmt.Sprintf("[restful] recover from panic situation: - %v\r\n", panicReason)) for i := 2; ; i += 1 { _, file, line, ok := runtime.Caller(i) if !ok { break } buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line)) } log.Print(buffer.String()) httpWriter.WriteHeader(http.StatusInternalServerError) httpWriter.Write(buffer.Bytes()) }
// Dispatch the incoming Http Request to a matching WebService. func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) { // Instal panic recovery unless told otherwise if !c.doNotRecover { // catch all for 500 response defer func() { if r := recover(); r != nil { c.recoverHandleFunc(r, httpWriter) return } }() } // Install closing the request body (if any) defer func() { if nil != httpRequest.Body { httpRequest.Body.Close() } }() // Detect if compression is needed // assume without compression, test for override writer := httpWriter if c.contentEncodingEnabled { doCompress, encoding := wantsCompressedResponse(httpRequest) if doCompress { var err error writer, err = NewCompressingResponseWriter(httpWriter, encoding) if err != nil { log.Print("[restful] unable to install compressor: ", err) httpWriter.WriteHeader(http.StatusInternalServerError) return } defer func() { writer.(*CompressingResponseWriter).Close() }() } } // Find best match Route ; err is non nil if no match was found webService, route, err := c.router.SelectRoute( c.webServices, httpRequest) if err != nil { // a non-200 response has already been written // run container filters anyway ; they should not touch the response... chain := FilterChain{Filters: c.containerFilters, Target: func(req *Request, resp *Response) { switch err.(type) { case ServiceError: ser := err.(ServiceError) c.serviceErrorHandleFunc(ser, req, resp) } // TODO }} chain.ProcessFilter(NewRequest(httpRequest), NewResponse(writer)) return } wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer, httpRequest) // pass through filters (if any) if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 { // compose filter chain allFilters := []FilterFunction{} allFilters = append(allFilters, c.containerFilters...) allFilters = append(allFilters, webService.filters...) allFilters = append(allFilters, route.Filters...) chain := FilterChain{Filters: allFilters, Target: func(req *Request, resp *Response) { // handle request by route after passing all filters route.Function(wrappedRequest, wrappedResponse) }} chain.ProcessFilter(wrappedRequest, wrappedResponse) } else { // no filters, handle request by route route.Function(wrappedRequest, wrappedResponse) } }
// ReturnsError is deprecated, use Returns instead. func (b *RouteBuilder) ReturnsError(code int, message string, model interface{}) *RouteBuilder { log.Print("ReturnsError is deprecated, use Returns instead.") return b.Returns(code, message, model) }