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, ¶ms) 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 = ¶ms 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 }