github.com/influx6/npkg@v0.8.8/nhttp/http.go (about)

     1  package nhttp
     2  
     3  import (
     4  	"encoding/base64"
     5  	"errors"
     6  	"io"
     7  	"mime"
     8  	"net/http"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/influx6/npkg"
    13  	"github.com/influx6/npkg/njson"
    14  )
    15  
    16  const (
    17  	maxsize = 32 << 40
    18  
    19  	// MultipartKey defines the key used to store multipart Form.
    20  	MultipartKey = "MultiPartForm"
    21  )
    22  
    23  // HTTPError defines custom error that can be used to specify
    24  // status code and message.
    25  type HTTPError struct {
    26  	Code int
    27  	Err  error
    28  }
    29  
    30  // Error returns error string. Implements error interface.
    31  func (h HTTPError) Error() string {
    32  	return h.Err.Error()
    33  }
    34  
    35  // Gzip Compression
    36  type gzipResponseWriter struct {
    37  	io.Writer
    38  	http.ResponseWriter
    39  }
    40  
    41  func (w gzipResponseWriter) Write(b []byte) (int, error) {
    42  	return w.Writer.Write(b)
    43  }
    44  
    45  // handlerImpl implements http.Handler interface.
    46  type handlerImpl struct {
    47  	ContextHandler
    48  }
    49  
    50  // ServeHTTP implements http.Handler.ServeHttp method.
    51  func (h handlerImpl) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    52  	ctx := NewContext(SetRequest(r), SetResponseWriter(w))
    53  	if err := ctx.InitForms(); err != nil {
    54  		http.Error(w, err.Error(), http.StatusBadRequest)
    55  		return
    56  	}
    57  
    58  	defer ctx.ClearFlashMessages()
    59  
    60  	if err := h.ContextHandler(ctx); err != nil {
    61  		if httperr, ok := err.(HTTPError); ok {
    62  			http.Error(w, httperr.Error(), httperr.Code)
    63  			return
    64  		}
    65  
    66  		http.Error(w, err.Error(), http.StatusBadRequest)
    67  		return
    68  	}
    69  }
    70  
    71  // HTTPFunc returns a http.HandleFunc which wraps the Handler for usage
    72  // with a server.
    73  func HTTPFunc(nx ContextHandler, befores ...func()) http.HandlerFunc {
    74  	return handlerImpl{ContextHandler: func(ctx *Ctx) error {
    75  		ctx.response.beforeFuncs = append(ctx.response.beforeFuncs, befores...)
    76  		return nx(ctx)
    77  	}}.ServeHTTP
    78  }
    79  
    80  // ServeHandler returns a http.Handler which serves request to the provided Handler.
    81  func ServeHandler(h ContextHandler) http.Handler {
    82  	return handlerImpl{ContextHandler: h}
    83  }
    84  
    85  // GetFileMimeType returns associated mime type for giving file extension.
    86  func GetFileMimeType(path string) string {
    87  	ext := filepath.Ext(path)
    88  	extVal := mime.TypeByExtension(ext)
    89  	if extVal == "" {
    90  		extVal = mediaTypes[ext]
    91  	}
    92  	return extVal
    93  }
    94  
    95  // JSONError writes the giving error message to the provided writer.
    96  func JSONError(w http.ResponseWriter, statusCode int, errorCode string, message string, err error) error {
    97  	w.WriteHeader(statusCode)
    98  
    99  	var encoder = njson.JSONB()
   100  	encoder.ObjectFor("error", func(enc npkg.ObjectEncoder) {
   101  		enc.String("message", message)
   102  		enc.Int("status_code", statusCode)
   103  		enc.String("error_code", errorCode)
   104  
   105  		if encodableErr, ok := err.(npkg.EncodableObject); ok {
   106  			enc.Object("incident", encodableErr)
   107  		}
   108  		enc.String("incident", err.Error())
   109  	})
   110  
   111  	var _, werr = encoder.WriteTo(w)
   112  	return werr
   113  }
   114  
   115  // ParseAuthorization returns the scheme and token of the Authorization string
   116  // if it's valid.
   117  func ParseAuthorization(val string) (authType string, token string, err error) {
   118  	authSplit := strings.SplitN(val, " ", 2)
   119  	if len(authSplit) != 2 {
   120  		err = errors.New("invalid authorization: Expected content: `AuthType Token`")
   121  		return
   122  	}
   123  
   124  	authType = strings.TrimSpace(authSplit[0])
   125  	token = strings.TrimSpace(authSplit[1])
   126  
   127  	return
   128  }
   129  
   130  // ParseTokens parses the base64 encoded token sent as part of the Authorization string,
   131  // It expects all parts of string to be seperated with ':', returning splitted slice.
   132  func ParseTokens(val string) ([]string, error) {
   133  	decoded, err := base64.StdEncoding.DecodeString(val)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	return strings.Split(string(decoded), ":"), nil
   139  }