app.go 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. package xweb
  2. import (
  3. "errors"
  4. "fmt"
  5. "html/template"
  6. "io/ioutil"
  7. "net/http"
  8. "os"
  9. "path"
  10. "path/filepath"
  11. "reflect"
  12. "regexp"
  13. "runtime"
  14. "strconv"
  15. "strings"
  16. "time"
  17. "app.yhyue.com/moapp/jybase/go-xweb/httpsession"
  18. "app.yhyue.com/moapp/jybase/go-xweb/log"
  19. )
  20. const (
  21. XSRF_TAG string = "_xsrf"
  22. )
  23. type App struct {
  24. BasePath string
  25. Name string //[SWH|+]
  26. Routes []Route
  27. RoutesEq map[string]map[string]Route
  28. filters []Filter
  29. Server *Server
  30. AppConfig *AppConfig
  31. Config map[string]interface{}
  32. Actions map[string]interface{}
  33. ActionsPath map[reflect.Type]string
  34. ActionsNamePath map[string]string
  35. FuncMaps template.FuncMap
  36. Logger *log.Logger
  37. VarMaps T
  38. SessionManager *httpsession.Manager //Session manager
  39. RootTemplate *template.Template
  40. ErrorTemplate *template.Template
  41. StaticVerMgr *StaticVerMgr
  42. TemplateMgr *TemplateMgr
  43. ContentEncoding string
  44. }
  45. const (
  46. Debug = iota + 1
  47. Product
  48. )
  49. type AppConfig struct {
  50. Mode int
  51. StaticDir string
  52. TemplateDir string
  53. SessionOn bool
  54. MaxUploadSize int64
  55. CookieSecret string
  56. StaticFileVersion bool
  57. CacheTemplates bool
  58. ReloadTemplates bool
  59. CheckXsrf bool
  60. SessionTimeout time.Duration
  61. FormMapToStruct bool //[SWH|+]
  62. EnableHttpCache bool //[SWH|+]
  63. }
  64. type Route struct {
  65. Path string //path string
  66. CompiledRegexp *regexp.Regexp //path regexp
  67. HttpMethods map[string]bool //GET POST HEAD DELETE etc.
  68. HandlerMethod string //struct method name
  69. HandlerElement reflect.Type //handler element
  70. }
  71. func NewApp(args ...string) *App {
  72. path := args[0]
  73. name := ""
  74. if len(args) == 1 {
  75. name = strings.Replace(path, "/", "_", -1)
  76. } else {
  77. name = args[1]
  78. }
  79. return &App{
  80. BasePath: path,
  81. Name: name, //[SWH|+]
  82. RoutesEq: make(map[string]map[string]Route),
  83. AppConfig: &AppConfig{
  84. Mode: Product,
  85. StaticDir: "static",
  86. TemplateDir: "templates",
  87. SessionOn: true,
  88. SessionTimeout: 3600,
  89. MaxUploadSize: 10 * 1024 * 1024,
  90. StaticFileVersion: true,
  91. CacheTemplates: true,
  92. ReloadTemplates: true,
  93. CheckXsrf: true,
  94. FormMapToStruct: true,
  95. },
  96. Config: map[string]interface{}{},
  97. Actions: map[string]interface{}{},
  98. ActionsPath: map[reflect.Type]string{},
  99. ActionsNamePath: map[string]string{},
  100. FuncMaps: defaultFuncs,
  101. VarMaps: T{},
  102. filters: make([]Filter, 0),
  103. StaticVerMgr: new(StaticVerMgr),
  104. TemplateMgr: new(TemplateMgr),
  105. }
  106. }
  107. func (a *App) initApp() {
  108. if a.AppConfig.StaticFileVersion {
  109. a.StaticVerMgr.Init(a, a.AppConfig.StaticDir)
  110. }
  111. if a.AppConfig.CacheTemplates {
  112. a.TemplateMgr.Init(a, a.AppConfig.TemplateDir, a.AppConfig.ReloadTemplates)
  113. }
  114. a.FuncMaps["StaticUrl"] = a.StaticUrl
  115. a.FuncMaps["XsrfName"] = XsrfName
  116. a.VarMaps["XwebVer"] = Version
  117. if a.AppConfig.SessionOn {
  118. if a.Server.SessionManager != nil {
  119. a.SessionManager = a.Server.SessionManager
  120. } else {
  121. a.SessionManager = httpsession.Default()
  122. if a.AppConfig.SessionTimeout > time.Second {
  123. a.SessionManager.SetMaxAge(a.AppConfig.SessionTimeout)
  124. }
  125. a.SessionManager.Run()
  126. }
  127. }
  128. if a.Logger == nil {
  129. a.Logger = a.Server.Logger
  130. }
  131. }
  132. func (a *App) SetStaticDir(dir string) {
  133. a.AppConfig.StaticDir = dir
  134. }
  135. func (a *App) SetTemplateDir(path string) {
  136. a.AppConfig.TemplateDir = path
  137. }
  138. func (a *App) getTemplatePath(name string) string {
  139. templateFile := path.Join(a.AppConfig.TemplateDir, name)
  140. if fileExists(templateFile) {
  141. return templateFile
  142. }
  143. return ""
  144. }
  145. func (app *App) SetConfig(name string, val interface{}) {
  146. app.Config[name] = val
  147. }
  148. func (app *App) GetConfig(name string) interface{} {
  149. return app.Config[name]
  150. }
  151. func (app *App) AddAction(cs ...interface{}) {
  152. for _, c := range cs {
  153. app.AddRouter(app.BasePath, c)
  154. }
  155. }
  156. func (app *App) AutoAction(cs ...interface{}) {
  157. for _, c := range cs {
  158. t := reflect.Indirect(reflect.ValueOf(c)).Type()
  159. name := t.Name()
  160. if strings.HasSuffix(name, "Action") {
  161. path := strings.ToLower(name[:len(name)-6])
  162. app.AddRouter(JoinPath(app.BasePath, path), c)
  163. } else {
  164. app.Warn("AutoAction needs a named ends with Action")
  165. }
  166. }
  167. }
  168. func (app *App) AddTmplVar(name string, varOrFun interface{}) {
  169. if reflect.TypeOf(varOrFun).Kind() == reflect.Func {
  170. app.FuncMaps[name] = varOrFun
  171. } else {
  172. app.VarMaps[name] = varOrFun
  173. }
  174. }
  175. func (app *App) AddTmplVars(t *T) {
  176. for name, value := range *t {
  177. app.AddTmplVar(name, value)
  178. }
  179. }
  180. func (app *App) AddFilter(filter Filter) {
  181. app.filters = append(app.filters, filter)
  182. }
  183. func (app *App) Debug(params ...interface{}) {
  184. args := append([]interface{}{"[" + app.Name + "]"}, params...)
  185. app.Logger.Debug(args...)
  186. }
  187. func (app *App) Info(params ...interface{}) {
  188. args := append([]interface{}{"[" + app.Name + "]"}, params...)
  189. app.Logger.Info(args...)
  190. }
  191. func (app *App) Warn(params ...interface{}) {
  192. args := append([]interface{}{"[" + app.Name + "]"}, params...)
  193. app.Logger.Warn(args...)
  194. }
  195. func (app *App) Error(params ...interface{}) {
  196. args := append([]interface{}{"[" + app.Name + "]"}, params...)
  197. app.Logger.Error(args...)
  198. }
  199. func (app *App) Fatal(params ...interface{}) {
  200. args := append([]interface{}{"[" + app.Name + "]"}, params...)
  201. app.Logger.Fatal(args...)
  202. }
  203. func (app *App) Panic(params ...interface{}) {
  204. args := append([]interface{}{"[" + app.Name + "]"}, params...)
  205. app.Logger.Panic(args...)
  206. }
  207. func (app *App) Debugf(format string, params ...interface{}) {
  208. app.Logger.Debugf("["+app.Name+"] "+format, params...)
  209. }
  210. func (app *App) Infof(format string, params ...interface{}) {
  211. app.Logger.Infof("["+app.Name+"] "+format, params...)
  212. }
  213. func (app *App) Warnf(format string, params ...interface{}) {
  214. app.Logger.Warnf("["+app.Name+"] "+format, params...)
  215. }
  216. func (app *App) Errorf(format string, params ...interface{}) {
  217. app.Logger.Errorf("["+app.Name+"] "+format, params...)
  218. }
  219. func (app *App) Fatalf(format string, params ...interface{}) {
  220. app.Logger.Fatalf("["+app.Name+"] "+format, params...)
  221. }
  222. func (app *App) Panicf(format string, params ...interface{}) {
  223. app.Logger.Panicf("["+app.Name+"] "+format, params...)
  224. }
  225. func (app *App) filter(w http.ResponseWriter, req *http.Request) bool {
  226. for _, filter := range app.filters {
  227. if !filter.Do(w, req) {
  228. return false
  229. }
  230. }
  231. return true
  232. }
  233. func (a *App) addRoute(r string, methods map[string]bool, t reflect.Type, handler string) {
  234. cr, err := regexp.Compile(r)
  235. if err != nil {
  236. a.Errorf("Error in route regex %q: %s", r, err)
  237. return
  238. }
  239. a.Routes = append(a.Routes, Route{Path: r, CompiledRegexp: cr, HttpMethods: methods, HandlerMethod: handler, HandlerElement: t})
  240. }
  241. func (a *App) addEqRoute(r string, methods map[string]bool, t reflect.Type, handler string) {
  242. if _, ok := a.RoutesEq[r]; !ok {
  243. a.RoutesEq[r] = make(map[string]Route)
  244. }
  245. for v, _ := range methods {
  246. a.RoutesEq[r][v] = Route{HandlerMethod: handler, HandlerElement: t}
  247. }
  248. }
  249. var (
  250. mapperType = reflect.TypeOf(Mapper{})
  251. )
  252. func (app *App) AddRouter(url string, c interface{}) {
  253. t := reflect.TypeOf(c).Elem()
  254. app.ActionsPath[t] = url
  255. app.Actions[t.Name()] = c
  256. app.ActionsNamePath[t.Name()] = url
  257. for i := 0; i < t.NumField(); i++ {
  258. if t.Field(i).Type != mapperType {
  259. continue
  260. }
  261. name := t.Field(i).Name
  262. a := strings.Title(name)
  263. v := reflect.ValueOf(c).MethodByName(a)
  264. if !v.IsValid() {
  265. continue
  266. }
  267. tag := t.Field(i).Tag
  268. tagStr := tag.Get("xweb")
  269. methods := map[string]bool{"GET": true, "POST": true}
  270. var p string
  271. var isEq bool
  272. if tagStr != "" {
  273. tags := strings.Split(tagStr, " ")
  274. path := tagStr
  275. length := len(tags)
  276. if length >= 2 {
  277. for _, method := range strings.Split(tags[0], "|") {
  278. methods[strings.ToUpper(method)] = true
  279. }
  280. path = tags[1]
  281. if regexp.QuoteMeta(path) == path {
  282. isEq = true
  283. }
  284. } else if length == 1 {
  285. if tags[0][0] == '/' {
  286. path = tags[0]
  287. if regexp.QuoteMeta(path) == path {
  288. isEq = true
  289. }
  290. } else {
  291. for _, method := range strings.Split(tags[0], "|") {
  292. methods[strings.ToUpper(method)] = true
  293. }
  294. path = "/" + name
  295. isEq = true
  296. }
  297. } else {
  298. path = "/" + name
  299. isEq = true
  300. }
  301. p = strings.TrimRight(url, "/") + path
  302. } else {
  303. p = strings.TrimRight(url, "/") + "/" + name
  304. isEq = true
  305. }
  306. if isEq {
  307. app.addEqRoute(removeStick(p), methods, t, a)
  308. } else {
  309. app.addRoute(removeStick(p), methods, t, a)
  310. }
  311. }
  312. }
  313. // the main route handler in web.go
  314. func (a *App) routeHandler(req *http.Request, w http.ResponseWriter) {
  315. requestPath := req.URL.Path
  316. var statusCode = 0
  317. defer func() {
  318. if statusCode == 0 {
  319. statusCode = 200
  320. }
  321. if statusCode >= 200 && statusCode < 400 {
  322. a.Info(req.Method, statusCode, requestPath)
  323. } else {
  324. a.Error(req.Method, statusCode, requestPath)
  325. }
  326. }()
  327. //ignore errors from ParseForm because it's usually harmless.
  328. ct := req.Header.Get("Content-Type")
  329. if strings.Contains(ct, "multipart/form-data") {
  330. req.ParseMultipartForm(a.AppConfig.MaxUploadSize)
  331. } else {
  332. req.ParseForm()
  333. }
  334. //set some default headers
  335. w.Header().Set("Server", "qfw")
  336. tm := time.Now().UTC()
  337. w.Header().Set("Date", webTime(tm))
  338. // static files, needed op
  339. if req.Method == "GET" || req.Method == "HEAD" {
  340. success := a.TryServingFile(requestPath, req, w)
  341. if success {
  342. statusCode = 200
  343. return
  344. }
  345. if requestPath == "/favicon.ico" {
  346. statusCode = 404
  347. a.error(w, 404, "Page not found")
  348. return
  349. }
  350. }
  351. //Set the default content-type
  352. w.Header().Set("Content-Type", "text/html; charset=utf-8")
  353. if !a.filter(w, req) {
  354. statusCode = 302
  355. return
  356. }
  357. requestPath = req.URL.Path //[SWH|+]support filter change req.URL.Path
  358. reqPath := removeStick(requestPath)
  359. allowMethod := Ternary(req.Method == "HEAD", "GET", req.Method).(string)
  360. isFind := false
  361. if routes, ok := a.RoutesEq[reqPath]; ok {
  362. if route, ok := routes[allowMethod]; ok {
  363. var isBreak bool = false
  364. var args []reflect.Value
  365. isBreak, statusCode = a.run(req, w, route, args)
  366. if isBreak {
  367. return
  368. }
  369. isFind = true
  370. }
  371. }
  372. if !isFind {
  373. for _, route := range a.Routes {
  374. cr := route.CompiledRegexp
  375. //if the methods don't match, skip this handler (except HEAD can be used in place of GET)
  376. if _, ok := route.HttpMethods[allowMethod]; !ok {
  377. continue
  378. }
  379. if !cr.MatchString(reqPath) {
  380. continue
  381. }
  382. match := cr.FindStringSubmatch(reqPath)
  383. if len(match[0]) != len(reqPath) {
  384. continue
  385. }
  386. var args []reflect.Value
  387. for _, arg := range match[1:] {
  388. args = append(args, reflect.ValueOf(arg))
  389. }
  390. var isBreak bool = false
  391. isBreak, statusCode = a.run(req, w, route, args)
  392. if isBreak {
  393. return
  394. }
  395. }
  396. }
  397. // try serving index.html or index.htm
  398. if req.Method == "GET" || req.Method == "HEAD" {
  399. if a.TryServingFile(path.Join(requestPath, "index.html"), req, w) {
  400. statusCode = 200
  401. return
  402. } else if a.TryServingFile(path.Join(requestPath, "index.htm"), req, w) {
  403. statusCode = 200
  404. return
  405. }
  406. }
  407. a.error(w, 404, "Page not found")
  408. statusCode = 404
  409. }
  410. func (a *App) run(req *http.Request, w http.ResponseWriter, route Route, args []reflect.Value) (isBreak bool, statusCode int) {
  411. vc := reflect.New(route.HandlerElement)
  412. c := &Action{
  413. Request: req,
  414. App: a,
  415. ResponseWriter: w,
  416. T: T{},
  417. f: T{},
  418. Option: &ActionOption{
  419. AutoMapForm: a.AppConfig.FormMapToStruct,
  420. CheckXsrf: a.AppConfig.CheckXsrf,
  421. },
  422. }
  423. for k, v := range a.VarMaps {
  424. c.T[k] = v
  425. }
  426. fieldA := vc.Elem().FieldByName("Action")
  427. //fieldA := fieldByName(vc.Elem(), "Action")
  428. if fieldA.IsValid() {
  429. fieldA.Set(reflect.ValueOf(c))
  430. }
  431. fieldC := vc.Elem().FieldByName("C")
  432. //fieldC := fieldByName(vc.Elem(), "C")
  433. if fieldC.IsValid() {
  434. fieldC.Set(reflect.ValueOf(vc))
  435. //fieldC.Set(vc)
  436. }
  437. initM := vc.MethodByName("Init")
  438. if initM.IsValid() {
  439. params := []reflect.Value{}
  440. initM.Call(params)
  441. }
  442. if c.Option.AutoMapForm {
  443. a.StructMap(vc.Elem(), req)
  444. }
  445. if c.Option.CheckXsrf && req.Method == "POST" {
  446. res, err := req.Cookie(XSRF_TAG)
  447. formVals := req.Form[XSRF_TAG]
  448. var formVal string
  449. if len(formVals) > 0 {
  450. formVal = formVals[0]
  451. }
  452. if err != nil || res.Value == "" || res.Value != formVal {
  453. a.error(w, 500, "xsrf token error.")
  454. a.Error("xsrf token error.")
  455. statusCode = 500
  456. isBreak = true
  457. return
  458. }
  459. }
  460. //[SWH|+]------------------------------------------Before-Hook
  461. structName := reflect.ValueOf(route.HandlerElement.Name())
  462. actionName := reflect.ValueOf(route.HandlerMethod)
  463. initM = vc.MethodByName("Before")
  464. if initM.IsValid() {
  465. structAction := []reflect.Value{structName, actionName}
  466. if ok := initM.Call(structAction); !ok[0].Bool() {
  467. isBreak = true
  468. return
  469. }
  470. }
  471. ret, err := a.SafelyCall(vc, route.HandlerMethod, args)
  472. if err != nil {
  473. //there was an error or panic while calling the handler
  474. if a.AppConfig.Mode == Debug {
  475. a.error(w, 500, fmt.Sprintf("<pre>handler error: %v</pre>", err))
  476. } else if a.AppConfig.Mode == Product {
  477. a.error(w, 500, "Server Error")
  478. }
  479. statusCode = 500
  480. isBreak = true
  481. return
  482. }
  483. statusCode = fieldA.Interface().(*Action).StatusCode
  484. //[SWH|+]------------------------------------------After-Hook
  485. initM = vc.MethodByName("After")
  486. if initM.IsValid() {
  487. structAction := []reflect.Value{structName, actionName}
  488. for _, v := range ret {
  489. structAction = append(structAction, v)
  490. }
  491. if len(structAction) != initM.Type().NumIn() {
  492. a.Error("Error : %v.After(): The number of params is not adapted.", structName)
  493. isBreak = true
  494. return
  495. }
  496. if ok := initM.Call(structAction); !ok[0].Bool() {
  497. isBreak = true
  498. return
  499. }
  500. }
  501. if len(ret) == 0 {
  502. isBreak = true
  503. return
  504. }
  505. sval := ret[0]
  506. var content []byte
  507. if sval.Interface() == nil || sval.Kind() == reflect.Bool {
  508. isBreak = true
  509. return
  510. } else if sval.Kind() == reflect.String {
  511. content = []byte(sval.String())
  512. } else if sval.Kind() == reflect.Slice && sval.Type().Elem().Kind() == reflect.Uint8 {
  513. content = sval.Interface().([]byte)
  514. } else if err, ok := sval.Interface().(error); ok {
  515. if err != nil {
  516. a.Error("Error:", err)
  517. a.error(w, 500, "Server Error")
  518. statusCode = 500
  519. }
  520. isBreak = true
  521. return
  522. } else {
  523. a.Warn("unkonw returned result type %v, ignored %v", sval,
  524. sval.Interface().(error))
  525. isBreak = true
  526. return
  527. }
  528. w.Header().Set("Content-Length", strconv.Itoa(len(content)))
  529. _, err = w.Write(content)
  530. if err != nil {
  531. a.Error("Error during write: %v", err)
  532. statusCode = 500
  533. isBreak = true
  534. return
  535. }
  536. return
  537. }
  538. func (a *App) error(w http.ResponseWriter, status int, content string) error {
  539. w.WriteHeader(status)
  540. if errorTmpl == "" {
  541. errTmplFile := a.AppConfig.TemplateDir + "/_error.html"
  542. if file, err := os.Stat(errTmplFile); err == nil && !file.IsDir() {
  543. if b, e := ioutil.ReadFile(errTmplFile); e == nil {
  544. errorTmpl = string(b)
  545. }
  546. }
  547. if errorTmpl == "" {
  548. errorTmpl = defaultErrorTmpl
  549. }
  550. }
  551. res := fmt.Sprintf(errorTmpl, status, statusText[status],
  552. status, statusText[status], content, Version)
  553. _, err := w.Write([]byte(res))
  554. return err
  555. }
  556. func (a *App) StaticUrl(url string) string {
  557. var basePath string
  558. if a.AppConfig.StaticDir == RootApp().AppConfig.StaticDir {
  559. basePath = RootApp().BasePath
  560. } else {
  561. basePath = a.BasePath
  562. }
  563. if !a.AppConfig.StaticFileVersion {
  564. return path.Join(basePath, url)
  565. }
  566. ver := a.StaticVerMgr.GetVersion(url)
  567. if ver == "" {
  568. return path.Join(basePath, url)
  569. }
  570. return path.Join(basePath, url+"?v="+ver)
  571. }
  572. // safelyCall invokes `function` in recover block
  573. func (a *App) SafelyCall(vc reflect.Value, method string, args []reflect.Value) (resp []reflect.Value, err error) {
  574. defer func() {
  575. if e := recover(); e != nil {
  576. if !a.Server.Config.RecoverPanic {
  577. // go back to panic
  578. panic(e)
  579. } else {
  580. resp = nil
  581. var content string
  582. content = fmt.Sprintf("Handler crashed with error: %v", e)
  583. for i := 1; ; i += 1 {
  584. _, file, line, ok := runtime.Caller(i)
  585. if !ok {
  586. break
  587. } else {
  588. content += "\n"
  589. }
  590. content += fmt.Sprintf("%v %v", file, line)
  591. }
  592. a.Error(content)
  593. err = errors.New(content)
  594. return
  595. }
  596. }
  597. }()
  598. function := vc.MethodByName(method)
  599. return function.Call(args), err
  600. }
  601. // Init content-length header.
  602. func (a *App) InitHeadContent(w http.ResponseWriter, contentLength int64) {
  603. if a.ContentEncoding == "gzip" {
  604. w.Header().Set("Content-Encoding", "gzip")
  605. } else if a.ContentEncoding == "deflate" {
  606. w.Header().Set("Content-Encoding", "deflate")
  607. } else {
  608. w.Header().Set("Content-Length", strconv.FormatInt(contentLength, 10))
  609. }
  610. }
  611. // tryServingFile attempts to serve a static file, and returns
  612. // whether or not the operation is successful.
  613. func (a *App) TryServingFile(name string, req *http.Request, w http.ResponseWriter) bool {
  614. newPath := name
  615. if strings.HasPrefix(name, a.BasePath) {
  616. newPath = name[len(a.BasePath):]
  617. }
  618. staticFile := filepath.Join(a.AppConfig.StaticDir, newPath)
  619. finfo, err := os.Stat(staticFile)
  620. if err != nil {
  621. return false
  622. }
  623. if !finfo.IsDir() {
  624. isStaticFileToCompress := false
  625. if a.Server.Config.EnableGzip && a.Server.Config.StaticExtensionsToGzip != nil && len(a.Server.Config.StaticExtensionsToGzip) > 0 {
  626. for _, statExtension := range a.Server.Config.StaticExtensionsToGzip {
  627. if strings.HasSuffix(strings.ToLower(staticFile), strings.ToLower(statExtension)) {
  628. isStaticFileToCompress = true
  629. break
  630. }
  631. }
  632. }
  633. if isStaticFileToCompress {
  634. a.ContentEncoding = GetAcceptEncodingZip(req)
  635. memzipfile, err := OpenMemZipFile(staticFile, a.ContentEncoding)
  636. if err != nil {
  637. return false
  638. }
  639. a.InitHeadContent(w, finfo.Size())
  640. http.ServeContent(w, req, staticFile, finfo.ModTime(), memzipfile)
  641. } else {
  642. http.ServeFile(w, req, staticFile)
  643. }
  644. return true
  645. }
  646. return false
  647. }
  648. var (
  649. sc *Action = &Action{}
  650. )
  651. // StructMap function mapping params to controller's properties
  652. func (a *App) StructMap(vc reflect.Value, r *http.Request) error {
  653. return a.namedStructMap(vc, r, "")
  654. }
  655. // user[name][test]
  656. func SplitJson(s string) ([]string, error) {
  657. res := make([]string, 0)
  658. var begin, end int
  659. var isleft bool
  660. for i, r := range s {
  661. switch r {
  662. case '[':
  663. isleft = true
  664. if i > 0 && s[i-1] != ']' {
  665. if begin == end {
  666. return nil, errors.New("unknow character")
  667. }
  668. res = append(res, s[begin:end+1])
  669. }
  670. begin = i + 1
  671. end = begin
  672. case ']':
  673. if !isleft {
  674. return nil, errors.New("unknow character")
  675. }
  676. isleft = false
  677. if begin != end {
  678. //return nil, errors.New("unknow character")
  679. res = append(res, s[begin:end+1])
  680. begin = i + 1
  681. end = begin
  682. }
  683. default:
  684. end = i
  685. }
  686. if i == len(s)-1 && begin != end {
  687. res = append(res, s[begin:end+1])
  688. }
  689. }
  690. return res, nil
  691. }
  692. func (a *App) namedStructMap(vc reflect.Value, r *http.Request, topName string) error {
  693. for k, t := range r.Form {
  694. if k == XSRF_TAG || k == "" {
  695. continue
  696. }
  697. if topName != "" {
  698. if !strings.HasPrefix(k, topName) {
  699. continue
  700. }
  701. k = k[len(topName)+1:]
  702. }
  703. v := t[0]
  704. names := strings.Split(k, ".")
  705. var err error
  706. if len(names) == 1 {
  707. names, err = SplitJson(k)
  708. if err != nil {
  709. a.Warn("Unrecognize form key", k, err)
  710. continue
  711. }
  712. }
  713. var value reflect.Value = vc
  714. for i, name := range names {
  715. name = strings.Title(name)
  716. if i != len(names)-1 {
  717. if value.Kind() != reflect.Struct {
  718. a.Warnf("arg error, value kind is %v", value.Kind())
  719. break
  720. }
  721. //fmt.Println(name)
  722. value = value.FieldByName(name)
  723. if !value.IsValid() {
  724. a.Warnf("(%v value is not valid %v)", name, value)
  725. break
  726. }
  727. if !value.CanSet() {
  728. a.Warnf("can not set %v -> %v", name, value.Interface())
  729. break
  730. }
  731. if value.Kind() == reflect.Ptr {
  732. if value.IsNil() {
  733. value.Set(reflect.New(value.Type().Elem()))
  734. }
  735. value = value.Elem()
  736. }
  737. } else {
  738. if value.Kind() != reflect.Struct {
  739. a.Warnf("arg error, value %v kind is %v", name, value.Kind())
  740. break
  741. }
  742. tv := value.FieldByName(name)
  743. if !tv.IsValid() {
  744. break
  745. }
  746. if !tv.CanSet() {
  747. a.Warnf("can not set %v to %v", k, tv)
  748. break
  749. }
  750. if tv.Kind() == reflect.Ptr {
  751. tv.Set(reflect.New(tv.Type().Elem()))
  752. tv = tv.Elem()
  753. }
  754. var l interface{}
  755. switch k := tv.Kind(); k {
  756. case reflect.String:
  757. l = v
  758. tv.Set(reflect.ValueOf(l))
  759. case reflect.Bool:
  760. l = (v != "false" && v != "0")
  761. tv.Set(reflect.ValueOf(l))
  762. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
  763. x, err := strconv.Atoi(v)
  764. if err != nil {
  765. a.Warnf("arg %v as int: %v", v, err)
  766. break
  767. }
  768. l = x
  769. //tv.set
  770. tv.Set(reflect.ValueOf(l))
  771. case reflect.Int64:
  772. x, err := strconv.ParseInt(v, 10, 64)
  773. if err != nil {
  774. a.Warnf("arg %v as int64: %v", v, err)
  775. break
  776. }
  777. l = x
  778. tv.Set(reflect.ValueOf(l))
  779. case reflect.Float32, reflect.Float64:
  780. x, err := strconv.ParseFloat(v, 64)
  781. if err != nil {
  782. a.Warnf("arg %v as float64: %v", v, err)
  783. break
  784. }
  785. l = x
  786. tv.Set(reflect.ValueOf(l))
  787. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  788. x, err := strconv.ParseUint(v, 10, 64)
  789. if err != nil {
  790. a.Warnf("arg %v as uint: %v", v, err)
  791. break
  792. }
  793. l = x
  794. tv.Set(reflect.ValueOf(l))
  795. case reflect.Struct:
  796. if tvf, ok := tv.Interface().(FromConversion); ok {
  797. err := tvf.FromString(v)
  798. if err != nil {
  799. a.Warnf("struct %v invoke FromString faild", tvf)
  800. }
  801. } else if tv.Type().String() == "time.Time" {
  802. x, err := time.Parse("2006-01-02 15:04:05.000 -0700", v)
  803. if err != nil {
  804. x, err = time.Parse("2006-01-02 15:04:05", v)
  805. if err != nil {
  806. x, err = time.Parse("2006-01-02", v)
  807. if err != nil {
  808. a.Warnf("unsupported time format %v, %v", v, err)
  809. break
  810. }
  811. }
  812. }
  813. l = x
  814. tv.Set(reflect.ValueOf(l))
  815. } else {
  816. a.Warn("can not set an struct which is not implement Fromconversion interface")
  817. }
  818. case reflect.Ptr:
  819. a.Warn("can not set an ptr of ptr")
  820. case reflect.Slice, reflect.Array:
  821. tt := tv.Type().Elem()
  822. tk := tt.Kind()
  823. if tk == reflect.String {
  824. tv.Set(reflect.ValueOf(t))
  825. break
  826. }
  827. if tv.IsNil() {
  828. tv.Set(reflect.MakeSlice(tv.Type(), len(t), len(t)))
  829. }
  830. for i, s := range t {
  831. var err error
  832. switch tk {
  833. case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int8, reflect.Int64:
  834. var v int64
  835. v, err = strconv.ParseInt(s, 10, tt.Bits())
  836. if err == nil {
  837. tv.Index(i).SetInt(v)
  838. }
  839. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  840. var v uint64
  841. v, err = strconv.ParseUint(s, 10, tt.Bits())
  842. if err == nil {
  843. tv.Index(i).SetUint(v)
  844. }
  845. case reflect.Float32, reflect.Float64:
  846. var v float64
  847. v, err = strconv.ParseFloat(s, tt.Bits())
  848. if err == nil {
  849. tv.Index(i).SetFloat(v)
  850. }
  851. case reflect.Bool:
  852. var v bool
  853. v, err = strconv.ParseBool(s)
  854. if err == nil {
  855. tv.Index(i).SetBool(v)
  856. }
  857. case reflect.Complex64, reflect.Complex128:
  858. // TODO:
  859. err = fmt.Errorf("unsupported slice element type %v", tk.String())
  860. default:
  861. err = fmt.Errorf("unsupported slice element type %v", tk.String())
  862. }
  863. if err != nil {
  864. a.Warnf("slice error: %v, %v", name, err)
  865. break
  866. }
  867. }
  868. default:
  869. a.Warnf("unknow mapping method", name)
  870. break
  871. }
  872. }
  873. }
  874. }
  875. return nil
  876. }
  877. func (app *App) Redirect(w http.ResponseWriter, requestPath, url string, status ...int) error {
  878. err := redirect(w, url, status...)
  879. if err != nil {
  880. app.Errorf("redirect error: %s", err)
  881. return err
  882. }
  883. return nil
  884. }
  885. func (app *App) Action(name string) interface{} {
  886. if v, ok := app.Actions[name]; ok {
  887. return v
  888. }
  889. return nil
  890. }
  891. /*
  892. example:
  893. {
  894. "AdminAction":{
  895. "Index":["GET","POST"],
  896. "Add": ["GET","POST"],
  897. "Edit": ["GET","POST"]
  898. }
  899. }
  900. */
  901. func (app *App) Nodes() (r map[string]map[string][]string) {
  902. r = make(map[string]map[string][]string)
  903. for _, val := range app.Routes {
  904. name := val.HandlerElement.Name()
  905. if _, ok := r[name]; !ok {
  906. r[name] = make(map[string][]string)
  907. }
  908. if _, ok := r[name][val.HandlerMethod]; !ok {
  909. r[name][val.HandlerMethod] = make([]string, 0)
  910. }
  911. for k, _ := range val.HttpMethods {
  912. r[name][val.HandlerMethod] = append(r[name][val.HandlerMethod], k) //FUNC1:[POST,GET]
  913. }
  914. }
  915. for _, vals := range app.RoutesEq {
  916. for k, v := range vals {
  917. name := v.HandlerElement.Name()
  918. if _, ok := r[name]; !ok {
  919. r[name] = make(map[string][]string)
  920. }
  921. if _, ok := r[name][v.HandlerMethod]; !ok {
  922. r[name][v.HandlerMethod] = make([]string, 0)
  923. }
  924. r[name][v.HandlerMethod] = append(r[name][v.HandlerMethod], k) //FUNC1:[POST,GET]
  925. }
  926. }
  927. return
  928. }