27b7a8f7 by MrLee.Kun

Merge pull request #1 from astaxie/develop

Develop
2 parents 491238ce c143a6ec
...@@ -499,6 +499,41 @@ func (c *Controller) GetFile(key string) (multipart.File, *multipart.FileHeader, ...@@ -499,6 +499,41 @@ func (c *Controller) GetFile(key string) (multipart.File, *multipart.FileHeader,
499 return c.Ctx.Request.FormFile(key) 499 return c.Ctx.Request.FormFile(key)
500 } 500 }
501 501
502 // GetFiles return multi-upload files
503 // files, err:=c.Getfiles("myfiles")
504 // if err != nil {
505 // http.Error(w, err.Error(), http.StatusNoContent)
506 // return
507 // }
508 // for i, _ := range files {
509 // //for each fileheader, get a handle to the actual file
510 // file, err := files[i].Open()
511 // defer file.Close()
512 // if err != nil {
513 // http.Error(w, err.Error(), http.StatusInternalServerError)
514 // return
515 // }
516 // //create destination file making sure the path is writeable.
517 // dst, err := os.Create("upload/" + files[i].Filename)
518 // defer dst.Close()
519 // if err != nil {
520 // http.Error(w, err.Error(), http.StatusInternalServerError)
521 // return
522 // }
523 // //copy the uploaded file to the destination file
524 // if _, err := io.Copy(dst, file); err != nil {
525 // http.Error(w, err.Error(), http.StatusInternalServerError)
526 // return
527 // }
528 // }
529 func (c *Controller) GetFiles(key string) ([]*multipart.FileHeader, error) {
530 files, ok := c.Ctx.Request.MultipartForm.File["key"]
531 if ok {
532 return files, nil
533 }
534 return nil, http.ErrMissingFile
535 }
536
502 // SaveToFile saves uploaded file to new path. 537 // SaveToFile saves uploaded file to new path.
503 // it only operates the first one of mutil-upload form file field. 538 // it only operates the first one of mutil-upload form file field.
504 func (c *Controller) SaveToFile(fromfile, tofile string) error { 539 func (c *Controller) SaveToFile(fromfile, tofile string) error {
......
...@@ -36,7 +36,6 @@ import ( ...@@ -36,7 +36,6 @@ import (
36 "crypto/tls" 36 "crypto/tls"
37 "encoding/json" 37 "encoding/json"
38 "encoding/xml" 38 "encoding/xml"
39 "fmt"
40 "io" 39 "io"
41 "io/ioutil" 40 "io/ioutil"
42 "log" 41 "log"
...@@ -48,26 +47,50 @@ import ( ...@@ -48,26 +47,50 @@ import (
48 "net/url" 47 "net/url"
49 "os" 48 "os"
50 "strings" 49 "strings"
50 "sync"
51 "time" 51 "time"
52 ) 52 )
53 53
54 var defaultSetting = BeegoHttpSettings{UserAgent: "beegoServer", ConnectTimeout: 60 * time.Second, ReadWriteTimeout: 60 * time.Second, Gzip: true} 54 var defaultSetting = BeegoHttpSettings{
55 UserAgent: "beegoServer",
56 ConnectTimeout: 60 * time.Second,
57 ReadWriteTimeout: 60 * time.Second,
58 Gzip: true,
59 DumpBody: true,
60 }
61
55 var defaultCookieJar http.CookieJar 62 var defaultCookieJar http.CookieJar
63 var settingMutex sync.Mutex
56 64
57 // createDefaultCookie creates a global cookiejar to store cookies. 65 // createDefaultCookie creates a global cookiejar to store cookies.
58 func createDefaultCookie() { 66 func createDefaultCookie() {
67 settingMutex.Lock()
68 defer settingMutex.Unlock()
59 defaultCookieJar, _ = cookiejar.New(nil) 69 defaultCookieJar, _ = cookiejar.New(nil)
60 } 70 }
61 71
62 // Overwrite default settings 72 // Overwrite default settings
63 func SetDefaultSetting(setting BeegoHttpSettings) { 73 func SetDefaultSetting(setting BeegoHttpSettings) {
74 settingMutex.Lock()
75 defer settingMutex.Unlock()
64 defaultSetting = setting 76 defaultSetting = setting
77 if defaultSetting.ConnectTimeout == 0 {
78 defaultSetting.ConnectTimeout = 60 * time.Second
79 }
80 if defaultSetting.ReadWriteTimeout == 0 {
81 defaultSetting.ReadWriteTimeout = 60 * time.Second
82 }
65 } 83 }
66 84
67 // return *BeegoHttpRequest with specific method 85 // return *BeegoHttpRequest with specific method
68 func newBeegoRequest(url, method string) *BeegoHttpRequest { 86 func NewBeegoRequest(rawurl, method string) *BeegoHttpRequest {
69 var resp http.Response 87 var resp http.Response
88 u, err := url.Parse(rawurl)
89 if err != nil {
90 log.Fatal(err)
91 }
70 req := http.Request{ 92 req := http.Request{
93 URL: u,
71 Method: method, 94 Method: method,
72 Header: make(http.Header), 95 Header: make(http.Header),
73 Proto: "HTTP/1.1", 96 Proto: "HTTP/1.1",
...@@ -75,7 +98,7 @@ func newBeegoRequest(url, method string) *BeegoHttpRequest { ...@@ -75,7 +98,7 @@ func newBeegoRequest(url, method string) *BeegoHttpRequest {
75 ProtoMinor: 1, 98 ProtoMinor: 1,
76 } 99 }
77 return &BeegoHttpRequest{ 100 return &BeegoHttpRequest{
78 url: url, 101 url: rawurl,
79 req: &req, 102 req: &req,
80 params: map[string]string{}, 103 params: map[string]string{},
81 files: map[string]string{}, 104 files: map[string]string{},
...@@ -86,27 +109,27 @@ func newBeegoRequest(url, method string) *BeegoHttpRequest { ...@@ -86,27 +109,27 @@ func newBeegoRequest(url, method string) *BeegoHttpRequest {
86 109
87 // Get returns *BeegoHttpRequest with GET method. 110 // Get returns *BeegoHttpRequest with GET method.
88 func Get(url string) *BeegoHttpRequest { 111 func Get(url string) *BeegoHttpRequest {
89 return newBeegoRequest(url, "GET") 112 return NewBeegoRequest(url, "GET")
90 } 113 }
91 114
92 // Post returns *BeegoHttpRequest with POST method. 115 // Post returns *BeegoHttpRequest with POST method.
93 func Post(url string) *BeegoHttpRequest { 116 func Post(url string) *BeegoHttpRequest {
94 return newBeegoRequest(url, "POST") 117 return NewBeegoRequest(url, "POST")
95 } 118 }
96 119
97 // Put returns *BeegoHttpRequest with PUT method. 120 // Put returns *BeegoHttpRequest with PUT method.
98 func Put(url string) *BeegoHttpRequest { 121 func Put(url string) *BeegoHttpRequest {
99 return newBeegoRequest(url, "PUT") 122 return NewBeegoRequest(url, "PUT")
100 } 123 }
101 124
102 // Delete returns *BeegoHttpRequest DELETE method. 125 // Delete returns *BeegoHttpRequest DELETE method.
103 func Delete(url string) *BeegoHttpRequest { 126 func Delete(url string) *BeegoHttpRequest {
104 return newBeegoRequest(url, "DELETE") 127 return NewBeegoRequest(url, "DELETE")
105 } 128 }
106 129
107 // Head returns *BeegoHttpRequest with HEAD method. 130 // Head returns *BeegoHttpRequest with HEAD method.
108 func Head(url string) *BeegoHttpRequest { 131 func Head(url string) *BeegoHttpRequest {
109 return newBeegoRequest(url, "HEAD") 132 return NewBeegoRequest(url, "HEAD")
110 } 133 }
111 134
112 // BeegoHttpSettings 135 // BeegoHttpSettings
...@@ -120,6 +143,7 @@ type BeegoHttpSettings struct { ...@@ -120,6 +143,7 @@ type BeegoHttpSettings struct {
120 Transport http.RoundTripper 143 Transport http.RoundTripper
121 EnableCookie bool 144 EnableCookie bool
122 Gzip bool 145 Gzip bool
146 DumpBody bool
123 } 147 }
124 148
125 // BeegoHttpRequest provides more useful methods for requesting one url than http.Request. 149 // BeegoHttpRequest provides more useful methods for requesting one url than http.Request.
...@@ -134,6 +158,11 @@ type BeegoHttpRequest struct { ...@@ -134,6 +158,11 @@ type BeegoHttpRequest struct {
134 dump []byte 158 dump []byte
135 } 159 }
136 160
161 // get request
162 func (b *BeegoHttpRequest) GetRequest() *http.Request {
163 return b.req
164 }
165
137 // Change request settings 166 // Change request settings
138 func (b *BeegoHttpRequest) Setting(setting BeegoHttpSettings) *BeegoHttpRequest { 167 func (b *BeegoHttpRequest) Setting(setting BeegoHttpSettings) *BeegoHttpRequest {
139 b.setting = setting 168 b.setting = setting
...@@ -153,14 +182,20 @@ func (b *BeegoHttpRequest) SetEnableCookie(enable bool) *BeegoHttpRequest { ...@@ -153,14 +182,20 @@ func (b *BeegoHttpRequest) SetEnableCookie(enable bool) *BeegoHttpRequest {
153 } 182 }
154 183
155 // SetUserAgent sets User-Agent header field 184 // SetUserAgent sets User-Agent header field
156 func (b *BeegoHttpRequest) SetUserAgent(userAgent string) *BeegoHttpRequest { 185 func (b *BeegoHttpRequest) SetUserAgent(useragent string) *BeegoHttpRequest {
157 b.setting.UserAgent = userAgent 186 b.setting.UserAgent = useragent
158 return b 187 return b
159 } 188 }
160 189
161 // Debug sets show debug or not when executing request. 190 // Debug sets show debug or not when executing request.
162 func (b *BeegoHttpRequest) Debug(isDebug bool) *BeegoHttpRequest { 191 func (b *BeegoHttpRequest) Debug(isdebug bool) *BeegoHttpRequest {
163 b.setting.ShowDebug = isDebug 192 b.setting.ShowDebug = isdebug
193 return b
194 }
195
196 // Dump Body.
197 func (b *BeegoHttpRequest) DumpBody(isdump bool) *BeegoHttpRequest {
198 b.setting.DumpBody = isdump
164 return b 199 return b
165 } 200 }
166 201
...@@ -279,21 +314,18 @@ func (b *BeegoHttpRequest) JsonBody(obj interface{}) (*BeegoHttpRequest, error) ...@@ -279,21 +314,18 @@ func (b *BeegoHttpRequest) JsonBody(obj interface{}) (*BeegoHttpRequest, error)
279 } 314 }
280 315
281 func (b *BeegoHttpRequest) buildUrl(paramBody string) { 316 func (b *BeegoHttpRequest) buildUrl(paramBody string) {
282 if paramBody == "" {
283 return
284 }
285 // build GET url with query string 317 // build GET url with query string
286 if b.req.Method == "GET" { 318 if b.req.Method == "GET" && len(paramBody) > 0 {
287 if strings.Index(b.url, "?") == -1 { 319 if strings.Index(b.url, "?") != -1 {
288 b.url = b.url + "?" + paramBody
289 } else {
290 b.url += "&" + paramBody 320 b.url += "&" + paramBody
321 } else {
322 b.url = b.url + "?" + paramBody
291 } 323 }
292 return 324 return
293 } 325 }
294 326
295 // build POST url and body 327 // build POST/PUT/PATCH url and body
296 if b.req.Method == "POST" && b.req.Body == nil { 328 if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH") && b.req.Body == nil {
297 // with files 329 // with files
298 if len(b.files) > 0 { 330 if len(b.files) > 0 {
299 pr, pw := io.Pipe() 331 pr, pw := io.Pipe()
...@@ -338,16 +370,29 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { ...@@ -338,16 +370,29 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
338 if b.resp.StatusCode != 0 { 370 if b.resp.StatusCode != 0 {
339 return b.resp, nil 371 return b.resp, nil
340 } 372 }
373 resp, err := b.SendOut()
374 if err != nil {
375 return nil, err
376 }
377 b.resp = resp
378 return resp, nil
379 }
380
381 func (b *BeegoHttpRequest) SendOut() (*http.Response, error) {
341 var paramBody string 382 var paramBody string
342 if len(b.params) > 0 { 383 if len(b.params) > 0 {
384 var buf bytes.Buffer
343 for k, v := range b.params { 385 for k, v := range b.params {
344 paramBody += fmt.Sprintf("&%s=%v", url.QueryEscape(k), url.QueryEscape(v)) 386 buf.WriteString(url.QueryEscape(k))
387 buf.WriteByte('=')
388 buf.WriteString(url.QueryEscape(v))
389 buf.WriteByte('&')
345 } 390 }
346 paramBody = paramBody[1:] 391 paramBody = buf.String()
392 paramBody = paramBody[0 : len(paramBody)-1]
347 } 393 }
348 394
349 b.buildUrl(paramBody) 395 b.buildUrl(paramBody)
350
351 url, err := url.Parse(b.url) 396 url, err := url.Parse(b.url)
352 if err != nil { 397 if err != nil {
353 return nil, err 398 return nil, err
...@@ -357,13 +402,6 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { ...@@ -357,13 +402,6 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
357 402
358 trans := b.setting.Transport 403 trans := b.setting.Transport
359 404
360 if b.setting.ConnectTimeout == 0 {
361 b.setting.ConnectTimeout = 60 * time.Second
362 }
363 if b.setting.ReadWriteTimeout == 0 {
364 b.setting.ReadWriteTimeout = 60 * time.Second
365 }
366
367 if trans == nil { 405 if trans == nil {
368 // create default transport 406 // create default transport
369 trans = &http.Transport{ 407 trans = &http.Transport{
...@@ -404,15 +442,13 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { ...@@ -404,15 +442,13 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
404 } 442 }
405 443
406 if b.setting.ShowDebug { 444 if b.setting.ShowDebug {
407 dump, err := httputil.DumpRequest(b.req, true) 445 dump, err := httputil.DumpRequest(b.req, b.setting.DumpBody)
408 if err != nil { 446 if err != nil {
409 log.Println(err.Error()) 447 log.Println(err.Error())
410 } 448 }
411 b.dump = dump 449 b.dump = dump
412 } 450 }
413 451 return client.Do(b.req)
414 b.resp, err = client.Do(b.req)
415 return b.resp, err
416 } 452 }
417 453
418 // String returns the body string in response. 454 // String returns the body string in response.
...@@ -433,9 +469,12 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) { ...@@ -433,9 +469,12 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
433 return b.body, nil 469 return b.body, nil
434 } 470 }
435 resp, err := b.getResponse() 471 resp, err := b.getResponse()
436 if resp == nil || resp.Body == nil { 472 if err != nil {
437 return nil, err 473 return nil, err
438 } 474 }
475 if resp.Body == nil {
476 return nil, nil
477 }
439 defer resp.Body.Close() 478 defer resp.Body.Close()
440 if b.setting.Gzip && resp.Header.Get("Content-Encoding") == "gzip" { 479 if b.setting.Gzip && resp.Header.Get("Content-Encoding") == "gzip" {
441 reader, err := gzip.NewReader(resp.Body) 480 reader, err := gzip.NewReader(resp.Body)
...@@ -452,18 +491,20 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) { ...@@ -452,18 +491,20 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
452 // ToFile saves the body data in response to one file. 491 // ToFile saves the body data in response to one file.
453 // it calls Response inner. 492 // it calls Response inner.
454 func (b *BeegoHttpRequest) ToFile(filename string) error { 493 func (b *BeegoHttpRequest) ToFile(filename string) error {
455 resp, err := b.getResponse()
456 if resp == nil || resp.Body == nil {
457 return err
458 }
459 defer resp.Body.Close()
460
461 f, err := os.Create(filename) 494 f, err := os.Create(filename)
462 if err != nil { 495 if err != nil {
463 return err 496 return err
464 } 497 }
465 defer f.Close() 498 defer f.Close()
466 499
500 resp, err := b.getResponse()
501 if err != nil {
502 return err
503 }
504 if resp.Body == nil {
505 return nil
506 }
507 defer resp.Body.Close()
467 _, err = io.Copy(f, resp.Body) 508 _, err = io.Copy(f, resp.Body)
468 return err 509 return err
469 } 510 }
......
...@@ -44,6 +44,8 @@ var ( ...@@ -44,6 +44,8 @@ var (
44 "gte": true, 44 "gte": true,
45 "lt": true, 45 "lt": true,
46 "lte": true, 46 "lte": true,
47 "eq": true,
48 "nq": true,
47 "startswith": true, 49 "startswith": true,
48 "endswith": true, 50 "endswith": true,
49 "istartswith": true, 51 "istartswith": true,
......
...@@ -30,6 +30,8 @@ var mysqlOperators = map[string]string{ ...@@ -30,6 +30,8 @@ var mysqlOperators = map[string]string{
30 "gte": ">= ?", 30 "gte": ">= ?",
31 "lt": "< ?", 31 "lt": "< ?",
32 "lte": "<= ?", 32 "lte": "<= ?",
33 "eq": "= ?",
34 "ne": "!= ?",
33 "startswith": "LIKE BINARY ?", 35 "startswith": "LIKE BINARY ?",
34 "endswith": "LIKE BINARY ?", 36 "endswith": "LIKE BINARY ?",
35 "istartswith": "LIKE ?", 37 "istartswith": "LIKE ?",
......
...@@ -29,6 +29,8 @@ var postgresOperators = map[string]string{ ...@@ -29,6 +29,8 @@ var postgresOperators = map[string]string{
29 "gte": ">= ?", 29 "gte": ">= ?",
30 "lt": "< ?", 30 "lt": "< ?",
31 "lte": "<= ?", 31 "lte": "<= ?",
32 "eq": "= ?",
33 "ne": "!= ?",
32 "startswith": "LIKE ?", 34 "startswith": "LIKE ?",
33 "endswith": "LIKE ?", 35 "endswith": "LIKE ?",
34 "istartswith": "LIKE UPPER(?)", 36 "istartswith": "LIKE UPPER(?)",
......
...@@ -29,6 +29,8 @@ var sqliteOperators = map[string]string{ ...@@ -29,6 +29,8 @@ var sqliteOperators = map[string]string{
29 "gte": ">= ?", 29 "gte": ">= ?",
30 "lt": "< ?", 30 "lt": "< ?",
31 "lte": "<= ?", 31 "lte": "<= ?",
32 "eq": "= ?",
33 "ne": "!= ?",
32 "startswith": "LIKE ? ESCAPE '\\'", 34 "startswith": "LIKE ? ESCAPE '\\'",
33 "endswith": "LIKE ? ESCAPE '\\'", 35 "endswith": "LIKE ? ESCAPE '\\'",
34 "istartswith": "LIKE ? ESCAPE '\\'", 36 "istartswith": "LIKE ? ESCAPE '\\'",
......
...@@ -611,19 +611,21 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -611,19 +611,21 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
611 if p.enableFilter { 611 if p.enableFilter {
612 if l, ok := p.filters[pos]; ok { 612 if l, ok := p.filters[pos]; ok {
613 for _, filterR := range l { 613 for _, filterR := range l {
614 if ok, p := filterR.ValidRouter(urlPath); ok { 614 if filterR.returnOnOutput && w.started {
615 for k, v := range p { 615 return true
616 }
617 if ok, params := filterR.ValidRouter(urlPath); ok {
618 for k, v := range params {
616 context.Input.Params[k] = v 619 context.Input.Params[k] = v
617 } 620 }
618 filterR.filterFunc(context) 621 filterR.filterFunc(context)
619 if filterR.returnOnOutput && w.started { 622 }
620 return true 623 if filterR.returnOnOutput && w.started {
621 } 624 return true
622 } 625 }
623 } 626 }
624 } 627 }
625 } 628 }
626
627 return false 629 return false
628 } 630 }
629 631
......
...@@ -444,7 +444,7 @@ func TestFilterAfterExec(t *testing.T) { ...@@ -444,7 +444,7 @@ func TestFilterAfterExec(t *testing.T) {
444 mux := NewControllerRegister() 444 mux := NewControllerRegister()
445 mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput) 445 mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput)
446 mux.InsertFilter(url, BeforeExec, beegoFilterNoOutput) 446 mux.InsertFilter(url, BeforeExec, beegoFilterNoOutput)
447 mux.InsertFilter(url, AfterExec, beegoAfterExec1) 447 mux.InsertFilter(url, AfterExec, beegoAfterExec1, false)
448 448
449 mux.Get(url, beegoFilterFunc) 449 mux.Get(url, beegoFilterFunc)
450 450
...@@ -506,7 +506,7 @@ func TestFilterFinishRouterMultiFirstOnly(t *testing.T) { ...@@ -506,7 +506,7 @@ func TestFilterFinishRouterMultiFirstOnly(t *testing.T) {
506 url := "/finishRouterMultiFirstOnly" 506 url := "/finishRouterMultiFirstOnly"
507 507
508 mux := NewControllerRegister() 508 mux := NewControllerRegister()
509 mux.InsertFilter(url, FinishRouter, beegoFinishRouter1) 509 mux.InsertFilter(url, FinishRouter, beegoFinishRouter1, false)
510 mux.InsertFilter(url, FinishRouter, beegoFinishRouter2) 510 mux.InsertFilter(url, FinishRouter, beegoFinishRouter2)
511 511
512 mux.Get(url, beegoFilterFunc) 512 mux.Get(url, beegoFilterFunc)
...@@ -534,7 +534,7 @@ func TestFilterFinishRouterMulti(t *testing.T) { ...@@ -534,7 +534,7 @@ func TestFilterFinishRouterMulti(t *testing.T) {
534 534
535 mux := NewControllerRegister() 535 mux := NewControllerRegister()
536 mux.InsertFilter(url, FinishRouter, beegoFinishRouter1, false) 536 mux.InsertFilter(url, FinishRouter, beegoFinishRouter1, false)
537 mux.InsertFilter(url, FinishRouter, beegoFinishRouter2) 537 mux.InsertFilter(url, FinishRouter, beegoFinishRouter2, false)
538 538
539 mux.Get(url, beegoFilterFunc) 539 mux.Get(url, beegoFilterFunc)
540 540
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!