Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
A
autoradio
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
ale
autoradio
Commits
a66ec9b3
Commit
a66ec9b3
authored
11 years ago
by
ale
Browse files
Options
Downloads
Patches
Plain Diff
drop our copy of ghost gzip handler
parent
bd485ef8
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
fe/gzip.go
+0
-205
0 additions, 205 deletions
fe/gzip.go
with
0 additions
and
205 deletions
fe/gzip.go
deleted
100644 → 0
+
0
−
205
View file @
bd485ef8
package
fe
import
(
"compress/gzip"
"io"
"net/http"
"strings"
)
// Slightly modified by ale@incal.net, based on:
// https://github.com/PuerkitoBio/ghost
// Thanks to Andrew Gerrand for inspiration:
// https://groups.google.com/d/msg/golang-nuts/eVnTcMwNVjM/4vYU8id9Q2UJ
//
// Also, node's Connect library implementation of the compress middleware:
// https://github.com/senchalabs/connect/blob/master/lib/middleware/compress.js
//
// And StackOverflow's explanation of Vary: Accept-Encoding header:
// http://stackoverflow.com/questions/7848796/what-does-varyaccept-encoding-mean
// Internal gzipped writer that satisfies both the (body) writer in gzipped format,
// and maintains the rest of the ResponseWriter interface for header manipulation.
type
gzipResponseWriter
struct
{
io
.
Writer
http
.
ResponseWriter
r
*
http
.
Request
// Keep a hold of the Request, for the filter function
filtered
bool
// Has the request been run through the filter function?
dogzip
bool
// Should we do GZIP compression for this request?
filterFn
func
(
http
.
ResponseWriter
,
*
http
.
Request
)
bool
}
// Make sure the filter function is applied.
func
(
w
*
gzipResponseWriter
)
applyFilter
()
{
if
!
w
.
filtered
{
if
w
.
dogzip
=
w
.
filterFn
(
w
,
w
.
r
);
w
.
dogzip
{
setGzipHeaders
(
w
.
Header
())
}
w
.
filtered
=
true
}
}
// Unambiguous Write() implementation (otherwise both ResponseWriter and Writer
// want to claim this method).
func
(
w
*
gzipResponseWriter
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
w
.
applyFilter
()
if
w
.
dogzip
{
// Write compressed
return
w
.
Writer
.
Write
(
b
)
}
// Write uncompressed
return
w
.
ResponseWriter
.
Write
(
b
)
}
// Intercept the WriteHeader call to correctly set the GZIP headers.
func
(
w
*
gzipResponseWriter
)
WriteHeader
(
code
int
)
{
w
.
applyFilter
()
w
.
ResponseWriter
.
WriteHeader
(
code
)
}
// Implement WrapWriter interface
func
(
w
*
gzipResponseWriter
)
WrappedWriter
()
http
.
ResponseWriter
{
return
w
.
ResponseWriter
}
var
(
defaultFilterTypes
=
[
...
]
string
{
"text/"
,
"javascript"
,
"json"
,
}
)
// Default filter to check if the response should be GZIPped.
// By default, all text (html, css, xml, ...), javascript and json
// content types are candidates for GZIP.
func
defaultFilter
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
bool
{
hdr
:=
w
.
Header
()
for
_
,
tp
:=
range
defaultFilterTypes
{
ok
:=
headerMatch
(
hdr
,
"Content-Type"
,
tp
)
if
ok
{
return
true
}
}
return
false
}
// GZIPHandlerFunc is the same as GZIPHandler, it is just a convenience
// signature that accepts a func(http.ResponseWriter, *http.Request) instead of
// a http.Handler interface. It saves the boilerplate http.HandlerFunc() cast.
func
GZIPHandlerFunc
(
h
http
.
HandlerFunc
,
filterFn
func
(
http
.
ResponseWriter
,
*
http
.
Request
)
bool
)
http
.
HandlerFunc
{
return
GZIPHandler
(
h
,
filterFn
)
}
// Gzip compression HTTP handler. If the client supports it, it compresses the response
// written by the wrapped handler. The filter function is called when the response is about
// to be written to determine if compression should be applied. If this argument is nil,
// the default filter will GZIP only content types containing /json|text|javascript/.
func
GZIPHandler
(
h
http
.
Handler
,
filterFn
func
(
http
.
ResponseWriter
,
*
http
.
Request
)
bool
)
http
.
HandlerFunc
{
if
filterFn
==
nil
{
filterFn
=
defaultFilter
}
return
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
_
,
ok
:=
getGzipWriter
(
w
);
ok
{
// Self-awareness, gzip handler is already set up
h
.
ServeHTTP
(
w
,
r
)
return
}
hdr
:=
w
.
Header
()
setVaryHeader
(
hdr
)
// Do nothing on a HEAD request
if
r
.
Method
==
"HEAD"
{
h
.
ServeHTTP
(
w
,
r
)
return
}
if
!
acceptsGzip
(
r
.
Header
)
{
// No gzip support from the client, return uncompressed
h
.
ServeHTTP
(
w
,
r
)
return
}
// Prepare a gzip response container
gz
:=
gzip
.
NewWriter
(
w
)
gzw
:=
&
gzipResponseWriter
{
Writer
:
gz
,
ResponseWriter
:
w
,
r
:
r
,
filterFn
:
filterFn
,
}
h
.
ServeHTTP
(
gzw
,
r
)
// Iff the handler completed successfully (no panic) and GZIP was indeed used, close the gzip writer,
// which seems to generate a Write to the underlying writer.
if
gzw
.
dogzip
{
gz
.
Close
()
}
}
}
// Add the vary by "accept-encoding" header if it is not already set.
func
setVaryHeader
(
hdr
http
.
Header
)
{
if
!
headerMatch
(
hdr
,
"Vary"
,
"accept-encoding"
)
{
hdr
.
Add
(
"Vary"
,
"Accept-Encoding"
)
}
}
// Checks if the client accepts GZIP-encoded responses.
func
acceptsGzip
(
hdr
http
.
Header
)
bool
{
ok
:=
headerMatch
(
hdr
,
"Accept-Encoding"
,
"gzip"
)
if
!
ok
{
ok
=
headerEquals
(
hdr
,
"Accept-Encoding"
,
"*"
)
}
return
ok
}
func
setGzipHeaders
(
hdr
http
.
Header
)
{
// The content-type will be explicitly set somewhere down the path of handlers
hdr
.
Set
(
"Content-Encoding"
,
"gzip"
)
hdr
.
Del
(
"Content-Length"
)
}
// Helper function to retrieve the gzip writer.
func
getGzipWriter
(
w
http
.
ResponseWriter
)
(
*
gzipResponseWriter
,
bool
)
{
gz
,
ok
:=
GetResponseWriter
(
w
,
func
(
tst
http
.
ResponseWriter
)
bool
{
_
,
ok
:=
tst
.
(
*
gzipResponseWriter
)
return
ok
})
if
ok
{
return
gz
.
(
*
gzipResponseWriter
),
true
}
return
nil
,
false
}
func
headerMatch
(
hdr
http
.
Header
,
name
,
s
string
)
bool
{
return
strings
.
Contains
(
hdr
.
Get
(
name
),
s
)
}
func
headerEquals
(
hdr
http
.
Header
,
name
,
s
string
)
bool
{
return
hdr
.
Get
(
name
)
==
s
}
// This interface can be implemented by an augmented ResponseWriter, so that
// it doesn't hide other augmented writers in the chain.
type
WrapWriter
interface
{
http
.
ResponseWriter
WrappedWriter
()
http
.
ResponseWriter
}
// Helper function to retrieve a specific ResponseWriter.
func
GetResponseWriter
(
w
http
.
ResponseWriter
,
predicate
func
(
http
.
ResponseWriter
)
bool
)
(
http
.
ResponseWriter
,
bool
)
{
for
{
// Check if this writer is the one we're looking for
if
w
!=
nil
&&
predicate
(
w
)
{
return
w
,
true
}
// If it is a WrapWriter, move back the chain of wrapped writers
ww
,
ok
:=
w
.
(
WrapWriter
)
if
!
ok
{
return
nil
,
false
}
w
=
ww
.
WrappedWriter
()
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment