gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/lib/serverendpoint.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lib
     8  
     9  import (
    10  	"encoding/json"
    11  
    12  	"gitee.com/zhaochuninhefei/cfssl-gm/api"
    13  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/caerrors"
    14  	http "gitee.com/zhaochuninhefei/gmgo/gmhttp"
    15  	log "gitee.com/zhaochuninhefei/zcgolog/zclog"
    16  )
    17  
    18  // serverEndpoint represents a particular endpoint (e.g. to "/api/v1/enroll")
    19  type serverEndpoint struct {
    20  	// Path is the path to the endpoint
    21  	Path string
    22  	// The HTTP methods ("GET", "POST", etc) which the function will handle
    23  	Methods []string
    24  	// The HTTP status code for a successful response
    25  	successRC int
    26  	// Handler is the handler function for this endpoint
    27  	Handler func(ctx *serverRequestContextImpl) (interface{}, error)
    28  	// Server which hosts this endpoint
    29  	Server *Server
    30  }
    31  
    32  // ServeHTTP encapsulates the call to underlying Handlers to handle the request
    33  // and return the response with a proper HTTP status code
    34  func (se *serverEndpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    35  	var resp interface{}
    36  	url := r.URL.String()
    37  	log.Debugf("Received request for %s", url)
    38  	w = newHTTPResponseWriter(r, w, se)
    39  	err := se.validateMethod(r)
    40  	if err == nil {
    41  		// Call the endpoint handler to handle the request.  The handler may
    42  		// a) return the response in the 'resp' variable below, or
    43  		// b) write the response one chunk at a time, which is appropriate if the response may be large
    44  		//    and we don't want the server to buffer the entire response in memory.
    45  		resp, err = se.Handler(newServerRequestContext(r, w, se))
    46  	}
    47  	he := getHTTPErr(err)
    48  	if he != nil {
    49  		// An error occurred
    50  		w.WriteHeader(he.GetStatusCode())
    51  		log.Infof(`%s %s %s %d %d "%s"`, r.RemoteAddr, r.Method, r.URL, he.GetStatusCode(), he.GetLocalCode(), he.GetLocalMsg())
    52  	} else {
    53  		// No error occurred
    54  		scode := se.getSuccessRC()
    55  		w.WriteHeader(scode)
    56  		log.Infof(`%s %s %s %d 0 "OK"`, r.RemoteAddr, r.Method, r.URL, scode)
    57  	}
    58  	// If a response was returned by the handler, write it now.
    59  	if resp != nil {
    60  		writeJSON(resp, w)
    61  	}
    62  	// If nothing has been written, write an empty string for the response
    63  	if !w.(*httpResponseWriter).writeCalled {
    64  		w.Write([]byte(`""`))
    65  	}
    66  	// If an error was returned by the handler, write it now.
    67  	w.Write([]byte(`,"errors":[`))
    68  	if he != nil {
    69  		rm := &api.ResponseMessage{Code: he.GetRemoteCode(), Message: he.GetRemoteMsg()}
    70  		writeJSON(rm, w)
    71  	}
    72  	// Write true or false for success
    73  	w.Write([]byte(`],"messages":[],"success":`))
    74  	if he != nil {
    75  		w.Write([]byte(`false}`))
    76  	} else {
    77  		w.Write([]byte(`true}`))
    78  	}
    79  	w.(http.Flusher).Flush()
    80  }
    81  
    82  func (se *serverEndpoint) getSuccessRC() int {
    83  	if se.successRC == 0 {
    84  		return 200
    85  	}
    86  	return se.successRC
    87  }
    88  
    89  // Validate that the HTTP method is supported for this endpoint
    90  func (se *serverEndpoint) validateMethod(r *http.Request) error {
    91  	for _, m := range se.Methods {
    92  		if m == r.Method {
    93  			return nil
    94  		}
    95  	}
    96  	return caerrors.NewHTTPErr(405, caerrors.ErrMethodNotAllowed, "Method %s is not allowed", r.Method)
    97  }
    98  
    99  // Get the top-most HTTP error from the cause stack.
   100  // If not found, create one with an unknown error code.
   101  func getHTTPErr(err error) *caerrors.HTTPErr {
   102  	if err == nil {
   103  		return nil
   104  	}
   105  	curErr := caerrors.GetCause(err)
   106  	if curErr == nil {
   107  		return caerrors.CreateHTTPErr(500, caerrors.ErrUnknown, err.Error())
   108  	}
   109  	return curErr
   110  
   111  }
   112  
   113  func writeJSON(obj interface{}, w http.ResponseWriter) {
   114  	enc := json.NewEncoder(w)
   115  	err := enc.Encode(obj)
   116  	if err != nil {
   117  		log.Errorf("Failed encoding response to JSON: %s", err)
   118  	}
   119  }
   120  func newHTTPResponseWriter(r *http.Request, w http.ResponseWriter, se *serverEndpoint) *httpResponseWriter {
   121  	return &httpResponseWriter{r: r, w: w, se: se}
   122  }
   123  
   124  type httpResponseWriter struct {
   125  	r                 *http.Request
   126  	w                 http.ResponseWriter
   127  	se                *serverEndpoint
   128  	writeHeaderCalled bool
   129  	writeCalled       bool
   130  }
   131  
   132  // Header returns the header map that will be sent by WriteHeader.
   133  func (hrw *httpResponseWriter) Header() http.Header {
   134  	return hrw.w.Header()
   135  }
   136  
   137  // WriteHeader sends an HTTP response header with status code.
   138  func (hrw *httpResponseWriter) WriteHeader(scode int) {
   139  	if !hrw.writeHeaderCalled {
   140  		w := hrw.w
   141  		w.Header().Set("Connection", "Keep-Alive")
   142  		if hrw.isHead() {
   143  			w.Header().Set("Content-Length", "0")
   144  		} else {
   145  			w.Header().Set("Transfer-Encoding", "chunked")
   146  			w.Header().Set("Content-Type", "application/json")
   147  		}
   148  		// Write the appropriate successful status code for this endpoint
   149  		if scode == http.StatusOK {
   150  			scode = hrw.se.getSuccessRC()
   151  		}
   152  		w.WriteHeader(scode)
   153  		hrw.writeHeaderCalled = true
   154  	}
   155  }
   156  
   157  // Write writes the data to the connection as part of an HTTP reply.
   158  func (hrw *httpResponseWriter) Write(buf []byte) (int, error) {
   159  	if hrw.isHead() {
   160  		return 0, nil
   161  	}
   162  	w := hrw.w
   163  	hrw.WriteHeader(http.StatusOK)
   164  	if !hrw.writeCalled {
   165  		// Write the header of the body of the result
   166  		b, err := w.Write([]byte(`{"result":`))
   167  		if err != nil {
   168  			return b, err
   169  		}
   170  		hrw.writeCalled = true
   171  	}
   172  	if buf == nil {
   173  		return 0, nil
   174  	}
   175  	return w.Write(buf)
   176  }
   177  
   178  func (hrw *httpResponseWriter) Flush() {
   179  	hrw.w.(http.Flusher).Flush()
   180  }
   181  
   182  func (hrw *httpResponseWriter) isHead() bool {
   183  	return hrw.r.Method == "HEAD"
   184  }