Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
beego
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
beego
Commits
3255a435
Commit
3255a435
authored
Apr 05, 2014
by
astaxie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
beego: move staticServer to New file
parent
73d757e3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
124 additions
and
139 deletions
+124
-139
memzipfile.go
memzipfile.go
+20
-45
router.go
router.go
+14
-94
staticfile.go
staticfile.go
+90
-0
No files found.
memzipfile.go
View file @
3255a435
...
...
@@ -14,12 +14,12 @@ import (
"time"
)
var
gmfim
map
[
string
]
*
MemFileInfo
=
make
(
map
[
string
]
*
M
emFileInfo
)
var
gmfim
map
[
string
]
*
memFileInfo
=
make
(
map
[
string
]
*
m
emFileInfo
)
var
lock
sync
.
RWMutex
// OpenMemZipFile returns MemFile object with a compressed static file.
// it's used for serve static file if gzip enable.
func
OpenMemZipFile
(
path
string
,
zip
string
)
(
*
M
emFile
,
error
)
{
func
openMemZipFile
(
path
string
,
zip
string
)
(
*
m
emFile
,
error
)
{
osfile
,
e
:=
os
.
Open
(
path
)
if
e
!=
nil
{
return
nil
,
e
...
...
@@ -36,12 +36,9 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) {
lock
.
RLock
()
cfi
,
ok
:=
gmfim
[
zip
+
":"
+
path
]
lock
.
RUnlock
()
if
ok
&&
cfi
.
ModTime
()
==
modtime
&&
cfi
.
fileSize
==
fileSize
{
}
else
{
if
!
(
ok
&&
cfi
.
ModTime
()
==
modtime
&&
cfi
.
fileSize
==
fileSize
)
{
var
content
[]
byte
if
zip
==
"gzip"
{
//将文件内容压缩到zipbuf中
var
zipbuf
bytes
.
Buffer
gzipwriter
,
e
:=
gzip
.
NewWriterLevel
(
&
zipbuf
,
gzip
.
BestCompression
)
if
e
!=
nil
{
...
...
@@ -52,13 +49,11 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) {
if
e
!=
nil
{
return
nil
,
e
}
//读zipbuf到content
content
,
e
=
ioutil
.
ReadAll
(
&
zipbuf
)
if
e
!=
nil
{
return
nil
,
e
}
}
else
if
zip
==
"deflate"
{
//将文件内容压缩到zipbuf中
var
zipbuf
bytes
.
Buffer
deflatewriter
,
e
:=
flate
.
NewWriter
(
&
zipbuf
,
flate
.
BestCompression
)
if
e
!=
nil
{
...
...
@@ -69,7 +64,6 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) {
if
e
!=
nil
{
return
nil
,
e
}
//将zipbuf读入到content
content
,
e
=
ioutil
.
ReadAll
(
&
zipbuf
)
if
e
!=
nil
{
return
nil
,
e
...
...
@@ -81,17 +75,17 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) {
}
}
cfi
=
&
M
emFileInfo
{
osfileinfo
,
modtime
,
content
,
int64
(
len
(
content
)),
fileSize
}
cfi
=
&
m
emFileInfo
{
osfileinfo
,
modtime
,
content
,
int64
(
len
(
content
)),
fileSize
}
lock
.
Lock
()
defer
lock
.
Unlock
()
gmfim
[
zip
+
":"
+
path
]
=
cfi
}
return
&
M
emFile
{
fi
:
cfi
,
offset
:
0
},
nil
return
&
m
emFile
{
fi
:
cfi
,
offset
:
0
},
nil
}
// MemFileInfo contains a compressed file bytes and file information.
// it implements os.FileInfo interface.
type
M
emFileInfo
struct
{
type
m
emFileInfo
struct
{
os
.
FileInfo
modTime
time
.
Time
content
[]
byte
...
...
@@ -100,62 +94,62 @@ type MemFileInfo struct {
}
// Name returns the compressed filename.
func
(
fi
*
M
emFileInfo
)
Name
()
string
{
func
(
fi
*
m
emFileInfo
)
Name
()
string
{
return
fi
.
Name
()
}
// Size returns the raw file content size, not compressed size.
func
(
fi
*
M
emFileInfo
)
Size
()
int64
{
func
(
fi
*
m
emFileInfo
)
Size
()
int64
{
return
fi
.
contentSize
}
// Mode returns file mode.
func
(
fi
*
M
emFileInfo
)
Mode
()
os
.
FileMode
{
func
(
fi
*
m
emFileInfo
)
Mode
()
os
.
FileMode
{
return
fi
.
Mode
()
}
// ModTime returns the last modified time of raw file.
func
(
fi
*
M
emFileInfo
)
ModTime
()
time
.
Time
{
func
(
fi
*
m
emFileInfo
)
ModTime
()
time
.
Time
{
return
fi
.
modTime
}
// IsDir returns the compressing file is a directory or not.
func
(
fi
*
M
emFileInfo
)
IsDir
()
bool
{
func
(
fi
*
m
emFileInfo
)
IsDir
()
bool
{
return
fi
.
IsDir
()
}
// return nil. implement the os.FileInfo interface method.
func
(
fi
*
M
emFileInfo
)
Sys
()
interface
{}
{
func
(
fi
*
m
emFileInfo
)
Sys
()
interface
{}
{
return
nil
}
// MemFile contains MemFileInfo and bytes offset when reading.
// it implements io.Reader,io.ReadCloser and io.Seeker.
type
M
emFile
struct
{
fi
*
M
emFileInfo
type
m
emFile
struct
{
fi
*
m
emFileInfo
offset
int64
}
// Close memfile.
func
(
f
*
M
emFile
)
Close
()
error
{
func
(
f
*
m
emFile
)
Close
()
error
{
return
nil
}
// Get os.FileInfo of memfile.
func
(
f
*
M
emFile
)
Stat
()
(
os
.
FileInfo
,
error
)
{
func
(
f
*
m
emFile
)
Stat
()
(
os
.
FileInfo
,
error
)
{
return
f
.
fi
,
nil
}
// read os.FileInfo of files in directory of memfile.
// it returns empty slice.
func
(
f
*
M
emFile
)
Readdir
(
count
int
)
([]
os
.
FileInfo
,
error
)
{
func
(
f
*
m
emFile
)
Readdir
(
count
int
)
([]
os
.
FileInfo
,
error
)
{
infos
:=
[]
os
.
FileInfo
{}
return
infos
,
nil
}
// Read bytes from the compressed file bytes.
func
(
f
*
M
emFile
)
Read
(
p
[]
byte
)
(
n
int
,
err
error
)
{
func
(
f
*
m
emFile
)
Read
(
p
[]
byte
)
(
n
int
,
err
error
)
{
if
len
(
f
.
fi
.
content
)
-
int
(
f
.
offset
)
>=
len
(
p
)
{
n
=
len
(
p
)
}
else
{
...
...
@@ -171,7 +165,7 @@ var errWhence = errors.New("Seek: invalid whence")
var
errOffset
=
errors
.
New
(
"Seek: invalid offset"
)
// Read bytes from the compressed file bytes by seeker.
func
(
f
*
M
emFile
)
Seek
(
offset
int64
,
whence
int
)
(
ret
int64
,
err
error
)
{
func
(
f
*
m
emFile
)
Seek
(
offset
int64
,
whence
int
)
(
ret
int64
,
err
error
)
{
switch
whence
{
default
:
return
0
,
errWhence
...
...
@@ -191,7 +185,7 @@ func (f *MemFile) Seek(offset int64, whence int) (ret int64, err error) {
// GetAcceptEncodingZip returns accept encoding format in http header.
// zip is first, then deflate if both accepted.
// If no accepted, return empty string.
func
G
etAcceptEncodingZip
(
r
*
http
.
Request
)
string
{
func
g
etAcceptEncodingZip
(
r
*
http
.
Request
)
string
{
ss
:=
r
.
Header
.
Get
(
"Accept-Encoding"
)
ss
=
strings
.
ToLower
(
ss
)
if
strings
.
Contains
(
ss
,
"gzip"
)
{
...
...
@@ -203,22 +197,3 @@ func GetAcceptEncodingZip(r *http.Request) string {
}
return
""
}
// CloseZWriter closes the io.Writer after compressing static file.
func
CloseZWriter
(
zwriter
io
.
Writer
)
{
if
zwriter
==
nil
{
return
}
switch
zwriter
.
(
type
)
{
case
*
gzip
.
Writer
:
zwriter
.
(
*
gzip
.
Writer
)
.
Close
()
case
*
flate
.
Writer
:
zwriter
.
(
*
flate
.
Writer
)
.
Close
()
//其他情况不close, 保持和默认(非压缩)行为一致
/*
case io.WriteCloser:
zwriter.(io.WriteCloser).Close()
*/
}
}
router.go
View file @
3255a435
...
...
@@ -7,8 +7,6 @@ import (
"net"
"net/http"
"net/url"
"os"
"path"
"reflect"
"regexp"
"runtime"
...
...
@@ -33,7 +31,7 @@ const (
var
(
// supported http methods.
HTTPMETHOD
=
[]
string
{
"get"
,
"post"
,
"put"
,
"delete"
,
"patch"
,
"options"
,
"head"
}
HTTPMETHOD
=
[]
string
{
"get"
,
"post"
,
"put"
,
"delete"
,
"patch"
,
"options"
,
"head"
,
"trace"
,
"connect"
}
// these beego.Controller's methods shouldn't reflect to AutoRouter
exceptMethod
=
[]
string
{
"Init"
,
"Prepare"
,
"Finish"
,
"Render"
,
"RenderString"
,
"RenderBytes"
,
"Redirect"
,
"Abort"
,
"StopRun"
,
"UrlFor"
,
"ServeJson"
,
"ServeJsonp"
,
...
...
@@ -544,86 +542,24 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
http
.
Error
(
w
,
"Method Not Allowed"
,
405
)
goto
Admin
}
if
do_filter
(
BeforeRouter
)
{
//static file server
if
serverStaticRouter
(
context
)
{
goto
Admin
}
//static file server
for
prefix
,
staticDir
:=
range
StaticDir
{
if
len
(
prefix
)
==
0
{
continue
}
if
r
.
URL
.
Path
==
"/favicon.ico"
{
file
:=
path
.
Join
(
staticDir
,
r
.
URL
.
Path
)
if
utils
.
FileExists
(
file
)
{
http
.
ServeFile
(
w
,
r
,
file
)
w
.
started
=
true
goto
Admin
}
}
if
strings
.
HasPrefix
(
r
.
URL
.
Path
,
prefix
)
{
if
len
(
r
.
URL
.
Path
)
>
len
(
prefix
)
&&
r
.
URL
.
Path
[
len
(
prefix
)]
!=
'/'
{
continue
}
if
r
.
URL
.
Path
==
prefix
&&
prefix
[
len
(
prefix
)
-
1
]
!=
'/'
{
http
.
Redirect
(
rw
,
r
,
r
.
URL
.
Path
+
"/"
,
302
)
goto
Admin
}
file
:=
path
.
Join
(
staticDir
,
r
.
URL
.
Path
[
len
(
prefix
)
:
])
finfo
,
err
:=
os
.
Stat
(
file
)
if
err
!=
nil
{
if
RunMode
==
"dev"
{
Warn
(
err
)
}
http
.
NotFound
(
w
,
r
)
goto
Admin
}
//if the request is dir and DirectoryIndex is false then
if
finfo
.
IsDir
()
&&
!
DirectoryIndex
{
middleware
.
Exception
(
"403"
,
rw
,
r
,
"403 Forbidden"
)
goto
Admin
}
//This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request
isStaticFileToCompress
:=
false
if
StaticExtensionsToGzip
!=
nil
&&
len
(
StaticExtensionsToGzip
)
>
0
{
for
_
,
statExtension
:=
range
StaticExtensionsToGzip
{
if
strings
.
HasSuffix
(
strings
.
ToLower
(
file
),
strings
.
ToLower
(
statExtension
))
{
isStaticFileToCompress
=
true
break
}
}
}
if
isStaticFileToCompress
{
if
EnableGzip
{
w
.
contentEncoding
=
GetAcceptEncodingZip
(
r
)
}
memzipfile
,
err
:=
OpenMemZipFile
(
file
,
w
.
contentEncoding
)
if
err
!=
nil
{
return
}
w
.
InitHeadContent
(
finfo
.
Size
())
http
.
ServeContent
(
w
,
r
,
file
,
finfo
.
ModTime
(),
memzipfile
)
}
else
{
http
.
ServeFile
(
w
,
r
,
file
)
}
w
.
started
=
true
goto
Admin
if
context
.
Input
.
IsPost
()
{
if
CopyRequestBody
&&
!
context
.
Input
.
IsUpload
()
{
context
.
Input
.
CopyBody
()
}
context
.
Input
.
ParseFormOrMulitForm
(
MaxMemory
)
}
if
do_filter
(
AfterStatic
)
{
if
do_filter
(
BeforeRouter
)
{
goto
Admin
}
if
CopyRequestBody
{
context
.
Input
.
Body
()
if
do_filter
(
AfterStatic
)
{
goto
Admin
}
if
context
.
Input
.
RunController
!=
nil
&&
context
.
Input
.
RunMethod
!=
""
{
...
...
@@ -757,9 +693,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
if
findrouter
{
if
r
.
Method
==
"POST"
{
r
.
ParseMultipartForm
(
MaxMemory
)
}
//execute middleware filters
if
do_filter
(
BeforeExec
)
{
goto
Admin
...
...
@@ -830,9 +763,8 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
}
Admin
:
do_filter
(
FinishRouter
)
Admin
:
//admin module record QPS
if
EnableAdmin
{
timeend
:=
time
.
Since
(
starttime
)
...
...
@@ -891,10 +823,9 @@ func (p *ControllerRegistor) getRunMethod(method string, context *beecontext.Con
//responseWriter is a wrapper for the http.ResponseWriter
//started set to true if response was written to then don't execute other handler
type
responseWriter
struct
{
writer
http
.
ResponseWriter
started
bool
status
int
contentEncoding
string
writer
http
.
ResponseWriter
started
bool
status
int
}
// Header returns the header map that will be sent by WriteHeader.
...
...
@@ -902,17 +833,6 @@ func (w *responseWriter) Header() http.Header {
return
w
.
writer
.
Header
()
}
// Init content-length header.
func
(
w
*
responseWriter
)
InitHeadContent
(
contentlength
int64
)
{
if
w
.
contentEncoding
==
"gzip"
{
w
.
Header
()
.
Set
(
"Content-Encoding"
,
"gzip"
)
}
else
if
w
.
contentEncoding
==
"deflate"
{
w
.
Header
()
.
Set
(
"Content-Encoding"
,
"deflate"
)
}
else
{
w
.
Header
()
.
Set
(
"Content-Length"
,
strconv
.
FormatInt
(
contentlength
,
10
))
}
}
// Write writes the data to the connection as part of an HTTP reply,
// and sets `started` to true.
// started means the response has sent out.
...
...
staticfile.go
0 → 100644
View file @
3255a435
package
beego
import
(
"net/http"
"os"
"path"
"strconv"
"strings"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/middleware"
"github.com/astaxie/beego/utils"
)
func
serverStaticRouter
(
ctx
*
context
.
Context
)
bool
{
requestPath
:=
ctx
.
Input
.
Request
.
URL
.
Path
for
prefix
,
staticDir
:=
range
StaticDir
{
if
len
(
prefix
)
==
0
{
continue
}
if
requestPath
==
"/favicon.ico"
{
file
:=
path
.
Join
(
staticDir
,
requestPath
)
if
utils
.
FileExists
(
file
)
{
http
.
ServeFile
(
ctx
.
ResponseWriter
,
ctx
.
Request
,
file
)
return
true
}
}
if
strings
.
HasPrefix
(
requestPath
,
prefix
)
{
if
len
(
requestPath
)
>
len
(
prefix
)
&&
requestPath
[
len
(
prefix
)]
!=
'/'
{
continue
}
if
requestPath
==
prefix
&&
prefix
[
len
(
prefix
)
-
1
]
!=
'/'
{
http
.
Redirect
(
ctx
.
ResponseWriter
,
ctx
.
Request
,
requestPath
+
"/"
,
302
)
return
true
}
file
:=
path
.
Join
(
staticDir
,
requestPath
[
len
(
prefix
)
:
])
finfo
,
err
:=
os
.
Stat
(
file
)
if
err
!=
nil
{
if
RunMode
==
"dev"
{
Warn
(
err
)
}
http
.
NotFound
(
ctx
.
ResponseWriter
,
ctx
.
Request
)
return
true
}
//if the request is dir and DirectoryIndex is false then
if
finfo
.
IsDir
()
&&
!
DirectoryIndex
{
middleware
.
Exception
(
"403"
,
ctx
.
ResponseWriter
,
ctx
.
Request
,
"403 Forbidden"
)
return
true
}
//This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request
isStaticFileToCompress
:=
false
if
StaticExtensionsToGzip
!=
nil
&&
len
(
StaticExtensionsToGzip
)
>
0
{
for
_
,
statExtension
:=
range
StaticExtensionsToGzip
{
if
strings
.
HasSuffix
(
strings
.
ToLower
(
file
),
strings
.
ToLower
(
statExtension
))
{
isStaticFileToCompress
=
true
break
}
}
}
if
isStaticFileToCompress
{
var
contentEncoding
string
if
EnableGzip
{
contentEncoding
=
getAcceptEncodingZip
(
ctx
.
Request
)
}
memzipfile
,
err
:=
openMemZipFile
(
file
,
contentEncoding
)
if
err
!=
nil
{
return
true
}
if
contentEncoding
==
"gzip"
{
ctx
.
Output
.
Header
(
"Content-Encoding"
,
"gzip"
)
}
else
if
contentEncoding
==
"deflate"
{
ctx
.
Output
.
Header
(
"Content-Encoding"
,
"deflate"
)
}
else
{
ctx
.
Output
.
Header
(
"Content-Length"
,
strconv
.
FormatInt
(
finfo
.
Size
(),
10
))
}
http
.
ServeContent
(
ctx
.
ResponseWriter
,
ctx
.
Request
,
file
,
finfo
.
ModTime
(),
memzipfile
)
}
else
{
http
.
ServeFile
(
ctx
.
ResponseWriter
,
ctx
.
Request
,
file
)
}
return
true
}
}
return
false
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment