gopkg.in/simversity/gottp.v3@v3.0.0-20160401065405-576cf030ca0e/request.go (about)

     1  package gottp
     2  
     3  import (
     4  	"compress/gzip"
     5  	"compress/zlib"
     6  	"log"
     7  	"net/http"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"gopkg.in/simversity/gottp.v3/utils"
    12  )
    13  
    14  //*http.Request, rw ResponseWriter
    15  
    16  const PAGE_SIZE = 30
    17  const SKIP = 0
    18  const serverUA = "Gottp Server"
    19  const ERROR = `Oops! An Internal Error occured while performing that action.
    20  Please try again later`
    21  
    22  type WireSender interface {
    23  	SendOverWire() utils.Q
    24  }
    25  
    26  type Paginator struct {
    27  	Skip  int
    28  	Limit int
    29  	Wlt   string
    30  	Wgt   string
    31  	Wkey  string
    32  	Ids   []string
    33  }
    34  
    35  func makeInt(val interface{}, fallback int) int {
    36  	switch val.(type) {
    37  	case int:
    38  		return val.(int)
    39  	case string:
    40  		_val := val.(string)
    41  		ret, err := strconv.Atoi(_val)
    42  		if err == nil {
    43  			return ret
    44  		}
    45  	case float64:
    46  		return int(val.(float64))
    47  	}
    48  	return fallback
    49  }
    50  
    51  func makeString(val interface{}) (ret string) {
    52  	switch val.(type) {
    53  	case string:
    54  		ret = val.(string)
    55  	case int:
    56  		val := val.(int)
    57  		ret = strconv.Itoa(val)
    58  	}
    59  	return
    60  }
    61  
    62  type Request struct {
    63  	Request    *http.Request
    64  	Writer     http.ResponseWriter
    65  	UrlArgs    *map[string]string
    66  	pipeOutput chan<- *utils.Q
    67  	pipeIndex  int
    68  	params     *utils.Q
    69  }
    70  
    71  func (r *Request) makeUrlArgs(params utils.Q) {
    72  	if r.UrlArgs != nil {
    73  		for key, value := range *r.UrlArgs {
    74  			params[key] = value
    75  		}
    76  	}
    77  }
    78  
    79  func (r *Request) GetPaginator() *Paginator {
    80  	p := Paginator{Limit: -1}
    81  	qp := r.GetArguments()
    82  	for key, value := range *qp {
    83  		switch key {
    84  		case "skip":
    85  			p.Skip = makeInt(value, SKIP)
    86  		case "limit":
    87  			p.Limit = makeInt(value, PAGE_SIZE)
    88  		case "wlt":
    89  			p.Wlt = makeString(value)
    90  		case "wgt":
    91  			p.Wgt = makeString(value)
    92  		case "wkey":
    93  			p.Wkey = makeString(value)
    94  		case "ids":
    95  			ids, ok := value.([]string)
    96  			if !ok {
    97  				id := value.(string)
    98  				p.Ids = []string{id}
    99  			} else {
   100  				p.Ids = ids
   101  			}
   102  		}
   103  	}
   104  
   105  	if p.Limit < 0 {
   106  		p.Limit = PAGE_SIZE
   107  	}
   108  
   109  	return &p
   110  }
   111  
   112  func (r *Request) makeUrlParams(params utils.Q) {
   113  	r.Request.ParseForm()
   114  	for key, value := range r.Request.Form {
   115  		length := len(value)
   116  		if length == 1 {
   117  			params[key] = value[0]
   118  		} else {
   119  			params[key] = value
   120  		}
   121  	}
   122  }
   123  
   124  func (r *Request) makeBodyParams(params utils.Q) {
   125  	//if (r.Request.Method == "PUT" || r.Request.Method == "POST") {
   126  	if r.Request.ContentLength != 0 {
   127  		utils.DecodeStream(r.Request.Body, &params)
   128  	}
   129  }
   130  
   131  func (r *Request) GetArguments() *utils.Q {
   132  	if r.params == nil {
   133  		params := utils.Q{}
   134  		r.makeUrlArgs(params)
   135  		r.makeBodyParams(params)
   136  		r.makeUrlParams(params)
   137  		r.params = &params
   138  	}
   139  
   140  	return r.params
   141  }
   142  
   143  func (r *Request) ConvertArguments(f interface{}) {
   144  	utils.Convert(r.GetArguments(), f)
   145  }
   146  
   147  func (r *Request) GetArgument(key string) interface{} {
   148  	args := *r.GetArguments()
   149  	return args[key]
   150  }
   151  
   152  func (r *Request) ConvertArgument(key string, f interface{}) {
   153  	args := *r.GetArguments()
   154  	val := args[key]
   155  	utils.Convert(val, f)
   156  }
   157  
   158  func (r *Request) Finish(data interface{}) []byte {
   159  	r.Writer.Header().Set("Server", serverUA)
   160  	r.Writer.Header().Set("Access-Control-Allow-Origin", "*")
   161  	r.Writer.Header().Set("Content-Type", "application/json")
   162  	return utils.Encoder(data)
   163  }
   164  
   165  func (r *Request) Redirect(url string, status int) {
   166  	log.Println("Redirecting to", url)
   167  	http.Redirect(r.Writer, r.Request, url, status)
   168  	return
   169  }
   170  
   171  func (r *Request) Write(data interface{}) {
   172  	var piped utils.Q
   173  
   174  	if v, ok := data.(WireSender); ok {
   175  		piped = v.SendOverWire()
   176  	} else {
   177  		piped = utils.Q{
   178  			"data":    data,
   179  			"status":  http.StatusOK,
   180  			"message": "",
   181  		}
   182  	}
   183  
   184  	if r.pipeOutput != nil {
   185  		piped["index"] = r.pipeIndex
   186  		r.pipeOutput <- &piped
   187  	} else if strings.Contains(
   188  		r.Request.Header.Get("Accept-Encoding"), "deflate",
   189  	) {
   190  		r.Writer.Header().Set("Content-Encoding", "deflate")
   191  
   192  		gz := zlib.NewWriter(r.Writer)
   193  		defer gz.Close()
   194  		gz.Write(r.Finish(piped))
   195  
   196  	} else if strings.Contains(
   197  		r.Request.Header.Get("Accept-Encoding"), "gzip",
   198  	) {
   199  		r.Writer.Header().Set("Content-Encoding", "gzip")
   200  
   201  		gz := gzip.NewWriter(r.Writer)
   202  		defer gz.Close()
   203  		gz.Write(r.Finish(piped))
   204  
   205  	} else {
   206  		r.Writer.Write(r.Finish(piped))
   207  	}
   208  }
   209  
   210  func (r *Request) Raise(e HttpError) {
   211  	r.Write(e)
   212  }
   213  
   214  func performRequest(handler Handler, p *Request) {
   215  	method := (*p).Request.Method
   216  
   217  	switch method {
   218  	case "GET":
   219  		handler.Get(p)
   220  	case "POST":
   221  		handler.Post(p)
   222  	case "PUT":
   223  		handler.Put(p)
   224  	case "DELETE":
   225  		handler.Delete(p)
   226  	case "HEAD":
   227  		handler.Head(p)
   228  	case "OPTIONS":
   229  		handler.Options(p)
   230  	case "PATCH":
   231  		handler.Patch(p)
   232  	default:
   233  		log.Println("Unsupported method", method)
   234  	}
   235  }
   236  
   237  func doRequest(request *Request, availableUrls *[]*Url) {
   238  	requestUrl := request.Request.URL.Path
   239  	defer Tracer.Notify(getTracerExtra(request))
   240  
   241  	for _, url := range *availableUrls {
   242  		urlArgs, err := url.MakeUrlArgs(&requestUrl)
   243  		if !err {
   244  			request.UrlArgs = urlArgs
   245  			performRequest(url.handler, request)
   246  			return
   247  		}
   248  	}
   249  
   250  	e := HttpError{404, requestUrl + " did not match any exposed urls."}
   251  	request.Raise(e)
   252  	return
   253  }