Giter Site home page Giter Site logo

gorilla / handlers Goto Github PK

View Code? Open in Web Editor NEW
1.6K 31.0 272.0 174 KB

Package gorilla/handlers is a collection of useful middleware for Go HTTP services & web applications 🛃

Home Page: https://gorilla.github.io

License: BSD 3-Clause "New" or "Revised" License

Go 98.85% Makefile 1.15%
go gorilla middleware http handler golang gorilla-web-toolkit

handlers's Introduction

gorilla/handlers

Testing Codecov GoDoc Sourcegraph

Package handlers is a collection of handlers (aka "HTTP middleware") for use with Go's net/http package (or any framework supporting http.Handler), including:

Other handlers are documented on the Gorilla website.

Example

A simple example using handlers.LoggingHandler and handlers.CompressHandler:

import (
    "net/http"
    "github.com/gorilla/handlers"
)

func main() {
    r := http.NewServeMux()

    // Only log requests to our admin dashboard to stdout
    r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard)))
    r.HandleFunc("/", ShowIndex)

    // Wrap our server with our gzip handler to gzip compress all responses.
    http.ListenAndServe(":8000", handlers.CompressHandler(r))
}

License

BSD licensed. See the included LICENSE file for details.

handlers's People

Contributors

abursavich avatar andyhaskell avatar benitogf avatar commit-master avatar coreydaley avatar damoye avatar dautushenka avatar dunglas avatar elithrar avatar fangdingjun avatar flyingmutant avatar hjr265 avatar jagregory avatar kisielk avatar mkevac avatar mlsquires avatar mmussomele avatar nailk avatar nickpresta avatar njohns-grovo avatar nwidger avatar saranrapjs avatar sayboras avatar sergeyt avatar stevvooe avatar stuartnelson3 avatar taion809 avatar uudashr avatar vincent-petithory avatar wathiede avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

handlers's Issues

CompressHandler: Do not compress small files

Compressing small responses basically just burns CPU without any benefit. As I see it, all requests are compressed when using CompressHandler. Would it be possible to have a parameter to set the lower bound?

CompressHandler: Ignore MIME types, re-use writers via sync.Pool

Note: raising this as an issue half as a reminder to address this, and to provide someone a chance to get to it before I can.

As per this great article on gzip performance: http://blog.klauspost.com/gzip-performance-for-go-webservers/

Quick example:

func (w *compressResponseWriter) Write(b []byte) (int, error) {
    // You'll need to *not* write the gzip content-encoding header based on the type.   
    h := w.ResponseWriter.Header()
    var ctype string
    if ctype = h.Get("Content-Type"); ctype == "" {
        ctype  = http.DetectContentType(b)
        h.Set("Content-Type", ctype)
    }

    // compressableTypes checks types against a []string of acceptable Content-Types
    if !compressableTypes(ctype) {
        // Write the uncompressed bytes to the response.
        w.ResponseWriter.Write(b)
        return
    }

    h.Del("Content-Length")
    return w.Writer.Write(b)
}

I'll update here before I begin work in earnest, but it won't be until after the weekend as I need to submit patches to the sessions stores first. If someone wants to pick this up before then (it's fairly straightforward patch) then just say so. Happy to guide you in writing tests as well.

`RecoveryLogger` should accept interface instead of struct!

This code is not designed well: https://github.com/gorilla/handlers/blob/master/recovery.go#L49

func RecoveryLogger(logger *log.Logger) RecoveryOption {
	return func(h http.Handler) {
		r := h.(*recoveryHandler)
		r.logger = logger
	}
}

You should avoid accepting structs and instead try to accept interfaces whenever possible. In this particular case, since you are only using the Println(...interface{}) method, you should create an interface for the input argument like this:

type Logger interface {
    Println(v ...interface{}}
}

This would allow users to pass a custom structured logger (e.g. Logrus), which might have some other fields/tags like environment, host, user, application etc. Unstructured logs in a highly distributed environment are totally useless.

Options request is passed through when Origin is not allowed

If the Origin is not allowed on a OPTIONS request, the CORS middleware will pass the request through to the next handler.

i.e. This test fails:

func TestCORSHandlerOptionsRequestMustNotBePassedToNextHandlerWhenOriginNotAllowed(t *testing.T) {
	r := newRequest("OPTIONS", "http://www.example.com/")
	r.Header.Set("Origin", r.URL.String())
	r.Header.Set(corsRequestMethodHeader, "GET")

	rr := httptest.NewRecorder()

	testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Fatal("Options request must not be passed to next handler")
	})

	CORS(AllowedOrigins([]string{}))(testHandler).ServeHTTP(rr, r)

	if status := rr.Code; status != http.StatusOK {
		t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
	}
}

I would have expected this request be met with a 200 OK with no CORS headers as per other CORS implementations.

We recently deploy badly configured CORS allowed origins for one of our apps and where getting 404's on preflight requests since the middleware was handling control back to the app.

If this is something you are interested in fixing I can spend some time on a PR.

cors handler does not work

import (
        "net/http"

        "github.com/gorilla/handlers"
        "github.com/gorilla/mux"
)                                                                                                                                                                                                                                                                                                             func main() {
        r := mux.NewRouter()

        // Apply the CORS middleware to our top-level router, with the defaults.
        http.ListenAndServe(":8200", handlers.CORS()(r))
}

When I do


$ http -v OPTIONS :8200/
OPTIONS / HTTP/1.1

Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 0
Host: localhost:8200                                                                                                                                   
User-Agent: HTTPie/0.9.2
                                         
                                                                                                                                                                                                                                                                                                                                                                                                                            
HTTP/1.1 404 Not Found                                                                                                                                 

Content-Length: 19
Content-Type: text/plain; charset=utf-8
Date: Fri, 05 May 2017 21:57:41 GMT
X-Content-Type-Options: nosniff

404 page not found        

There is nothing related with the CORS in the response headers as you can see.
Am I missing something?
Is this feature tested?

Support both Alice and Negroni

Would you be at all interested in something like I wrote here: https://github.com/doug/middleware being included in gorilla/handlers. Or at least maybe formatting handlers so they can support both composing(functions(like(this))) and be an interface for the next handler. The issue I have with only supporting composition is you can't modify the stack or part of it once it is arranged.

A proposal.

package handlers

import (
    "compress/gzip"
    "net/http"
    "strings"
)

type gzipResponseWriter struct {
    *gzip.Writer
    http.ResponseWriter
}

func (w *gzipResponseWriter) Header() http.Header {
    return w.ResponseWriter.Header()
}

func (w *gzipResponseWriter) Write(b []byte) (int, error) {
    h := w.ResponseWriter.Header()
    if h.Get("Content-Type") == "" {
        h.Set("Content-Type", http.DetectContentType(b))
    }

    return w.Writer.Write(b)
}

type compress struct {}

func (c *compress) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
L:
    for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") {
        switch enc {
        case "gzip":
            w.Header().Set("Content-Encoding", "gzip")
            w.Header().Add("Vary", "Accept-Encoding")

            gw := gzip.NewWriter(w)
            defer gw.Close()

            w = &gzipResponseWriter{
                Writer:         gw,
                ResponseWriter: w,
            }
            break L
        }
    }

    next(w, r)

}

var Compress = &compress{}

type Middleware interface {
    ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

func Compose(m Middleware) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
            m.ServeHTTP(rw, r, next.ServeHTTP)
        })
    }
}

var CompressHandler = Compose(Compress)

ProxyHeaders: Support X-Forwarded-Host

X-Forwarded-Host is a de facto standard for identifying the original host requested by the client in the Host HTTP request header, since the host name and/or port of the reverse proxy (load balancer) may differ from the origin server handling the request.[0]
Currently I have an API gateway in front so the end application/endpoint can receives the original host via X-Forwarded-Host header.

[0] https://en.wikipedia.org/wiki/List_of_HTTP_header_fields

[ci] Investigate Failing CORS Tests on Go tip

https://travis-ci.org/gorilla/handlers/jobs/115421848#L206-L237

--- FAIL: TestCORSHandlerSetsExposedHeaders (0.00s)
    cors_test.go:72: bad header: expected X-Cors-Test header, got empty header for method.
=== RUN   TestCORSHandlerUnsetRequestMethodForPreflightBadRequest
--- PASS: TestCORSHandlerUnsetRequestMethodForPreflightBadRequest (0.00s)
=== RUN   TestCORSHandlerInvalidRequestMethodForPreflightMethodNotAllowed
--- PASS: TestCORSHandlerInvalidRequestMethodForPreflightMethodNotAllowed (0.00s)
=== RUN   TestCORSHandlerAllowedMethodForPreflight
--- FAIL: TestCORSHandlerAllowedMethodForPreflight (0.00s)
    cors_test.go:124: bad header: expected DELETE method header, got empty header.
=== RUN   TestCORSHandlerAllowMethodsNotSetForSimpleRequestPreflight
--- PASS: TestCORSHandlerAllowMethodsNotSetForSimpleRequestPreflight (0.00s)
=== RUN   TestCORSHandlerAllowedHeaderNotSetForSimpleRequestPreflight
--- PASS: TestCORSHandlerAllowedHeaderNotSetForSimpleRequestPreflight (0.00s)
=== RUN   TestCORSHandlerAllowedHeaderForPreflight
--- FAIL: TestCORSHandlerAllowedHeaderForPreflight (0.00s)
    cors_test.go:193: bad header: expected Content-Type header, got empty header.
=== RUN   TestCORSHandlerInvalidHeaderForPreflightForbidden
--- PASS: TestCORSHandlerInvalidHeaderForPreflightForbidden (0.00s)
=== RUN   TestCORSHandlerMaxAgeForPreflight
--- FAIL: TestCORSHandlerMaxAgeForPreflight (0.00s)
    cors_test.go:231: bad header: expected Access-Control-Max-Age to be 600, got .
=== RUN   TestCORSHandlerAllowedCredentials
--- FAIL: TestCORSHandlerAllowedCredentials (0.00s)
    cors_test.go:251: bad header: expected Access-Control-Allow-Credentials to be true, got .
=== RUN   TestCORSHandlerMultipleAllowOriginsSetsVaryHeader
--- FAIL: TestCORSHandlerMultipleAllowOriginsSetsVaryHeader (0.00s)
    cors_test.go:271: bad header: expected Vary to be Origin, got .
=== RUN   TestCORSWithMultipleHandlers
--- PASS: TestCORSWithMultipleHandlers (0.00s)
=== RUN   TestCORSHandlerWithCustomValidator
--- FAIL: TestCORSHandlerWithCustomValidator (0.00s)
    cors_test.go:315: bad header: expected Access-Control-Allow-Origin to be http://a.example.com, got .

Ping @njohns-grovo if you have time. I'm just lodging this as a reminder to dig deeper—it could just be a transient issue with tip.

Logging handler not defined

undefined: handlers.LoggingHandler
also,

LoggingHandler is not defined in $GOPATH/src/github/gorilla/handlers

Do a repository release

Go dependency management tools like Gom use a particular commitid/ tag to checkout the dependencies. Since this repo doesn't have a tag users have to stick to commitids, which is not clean and hard to track.

Set up CORS on Subrouter

I am facing some problems setting up the CORS handler when using a sub router, The specific needs is that I would like to set up the handler to answer specific paths, but that implies that I use mux.Router.Methods() and mux.Router.Path(). How can I use handlers.CORS properly?

This is the code that is not providing an answer when using OPTIONS as method:

func setRoutes(mr *mux.Router) {
	s := mr.PathPrefix("/objects").Subrouter()

	headersOk := handlers.AllowedHeaders([]string{"*"})
  originsOk := handlers.AllowedOrigins([]string{"*"})
  methodsOk := handlers.AllowedMethods([]string{"GET", "POST", "DELETE"})
	CORSCheck := handlers.CORS(headersOk, originsOk, methodsOk)

	baseMiddlewares := alice.New(CORSCheck, Auth.HTTPMiddleware)

	listCombo := baseMiddlewares.Then(http.HandlerFunc(listObj))
	s.Methods("GET", "OPTIONS").Path("/").Handler(listCombo)

	createCombo := baseMiddlewares.Then(http.HandlerFunc(createObj))
	s.Methods("POST").Path("/").Handler(createCombo)

	deleteCombo := baseMiddlewares.Then(http.HandlerFunc(deleteObj))
	s.Methods("DELETE", "OPTIONS").Path("/:uuid").Handler(deleteCombo)
}

I have even tried to set up a single path like that:

s.Methods("OPTIONS").Path("/").Handler(CORSCheck(emptyAnswerHandler))

Any suggestion? Am I forced to set up CORS on the very first set up of the http server?

DELETE CORS Requests

I cannot get DELETE requests to work.

http server

    methods := handlers.AllowedMethods([]string{"OPTIONS", "DELETE", "GET", "HEAD", "POST"})
    origins := handlers.AllowedOrigins([]string{"*"})

    server := &http.Server{
        Addr:    addr,
        Handler: handlers.CORS(methods, origins)(k.router),
    }

Router

router.HandleFunc("/sessions", controller.GetSessionsHandler).Methods("GET", "DELETE")

The request

XMLHttpRequest cannot load http://localhost:9228/sessions. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:9228' is therefore not allowed access. The response had HTTP status code 403.

Disallowing GET through CORS doesn't work

I am trying to disallow GET request through CORS headers. But it doesn't seem to work.

This is the code.

package main

import (
        "encoding/json"
        "net/http"

        "github.com/gorilla/handlers"
        "github.com/gorilla/mux"
)

func main() {
        https := &http.Server{
                Addr: ":8080",
        }

        r := mux.NewRouter()

        r.HandleFunc("/", hello)

        methods := handlers.AllowedMethods([]string{"HEAD", "POST", "OPTIONS"})

        https.Handler = handlers.CORS(methods)(r)

        https.ListenAndServe()
}

func hello(w http.ResponseWriter, r *http.Request) {
        json.NewEncoder(w).Encode("hello!")
}

This still works, even when GET is not in the allowed methods

(await fetch("http://127.0.0.1:8080")).json() => hello!

CompressHandler fix

Running curl --compress http://mysite showed that the CompressHandler wasn't being used. The header curl sends is Accept-Encoding: deflate, gzip.

This fixes the problem:

--- a/compress.go
+++ b/compress.go
@@ -32,7 +32,7 @@ func CompressHandler(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        L:
                for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") {
-                       switch enc {
+                       switch strings.TrimSpace(enc) {
                        case "gzip":
                                w.Header().Set("Content-Encoding", "gzip")
                                w.Header().Add("Vary", "Accept-Encoding")

Cannot change req.URL.User

The req.URL.User cannot be changed after the logging handler started. To keep the req.URL "read only", the following change would be great:

 diff --git a/handlers.go b/handlers.go
 index 23a738d..6a58644 100644
 --- a/handlers.go
 +++ b/handlers.go
 @@ -73,6 +73,9 @@ func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
         }
         url := *req.URL
         h.handler.ServeHTTP(logger, req)
 +       if req.URL.User != nil {
 +               url.User = req.URL.User
 +       }
         writeLog(h.writer, req, url, t, logger.Status(), logger.Size())
  }

 @@ -86,6 +89,9 @@ func (h combinedLoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Reque
         }
         url := *req.URL
         h.handler.ServeHTTP(logger, req)
 +       if req.URL.User != nil {
 +               url.User = req.URL.User
 +       }
         writeCombinedLog(h.writer, req, url, t, logger.Status(), logger.Size())
  }

Let me know if you want a PR for that.

Log response time

I'd like to discuss possibility a handler for logging response time.

I'm looking to log that info in a redis instance and see if I'm getting any spikes. (of course, I'll pass my own writer there)

Either I'm looking at this wrong way, or maybe it's useful for someone else too?

is this compatible with alice

hi gorilla team,

i am using justinas/alice for chaning handlers. (middleware)

i want use LoggingHandler that handler of "gorilla/handlers" package, but i can not do it. is this compatible with that ?

breaking change with returned Access-Control-Allow-Origin header

Prior to #116, specifying AllowedOriginValidator acted as an override to AllowedOrigins. Afterwards, the same configuration will return Access-Control-Allow-Origin: * because of the default value for allowedOrigins.

// before: will only reflect allowed origins
// after: will reflect "*"
gorilla.CORS(
  gorilla.AllowedOriginValidator(myValidator)
)

Fixing this requires specifying a blank AllowedOrigins to override the default value:

gorilla.CORS(
  gorilla.AllowedOrigins([]string{})
  gorilla.AllowedOriginValidator(myValidator)
)

Tag another release

v1.1 was done in February, and is missing some important functionality (at least in the CORS handler).

Need LICENSE file

The code headers indicate that there should be a BSD-style LICENSE file

can't find import: "github.com/gorilla/context"

I'm trying to deploy an app to appengine, which used to work fine, all of a sudden I'm getting this error message. Not sure if it's an issue with app engine, my code, gorilla/handlers or go...

source is here: https://github.com/wayneashleyberry/wayneashleyberry.com

❯ gcloud app deploy
You are about to deploy the following services:
 - wayneashleyberry-com/default/20160912t185450 (from [/Users/Wayne/src/github.com/wayneashleyberry/wayneashleyberry.com/app.yaml])
     Deployed URL: [https://wayneashleyberry-com.appspot.com]

Do you want to continue (Y/n)?  y

Beginning deployment of service [default]...
WARNING: Some files were skipped. Check the gcloud log file or pass `--verbosity=info` to see which ones.
File upload done.
Updating service [default]...failed.
ERROR: (gcloud.app.deploy) Error Response: [9] Deployment contains files that cannot be compiled: Compile failed:
2016/09/12 09:55:04 go-app-builder: build timing: 1×compile (103ms total), 0×link (0 total)
2016/09/12 09:55:04 go-app-builder: failed running compile: exit status 1

website/website.go:8: can't find import: "github.com/gorilla/handlers"

Canonical Host doesn't redirect /

handlers.CanonicalHost doesn't redirect http://example.com to https://example.com.

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()
    canonical := handlers.CanonicalHost("https://localhost:8080", 301)
    r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, World!")
    })

    log.Fatal(http.ListenAndServe(":8080", canonical(r)))
}
~
△ curl -v http://localhost:8080
* Rebuilt URL to: http://localhost:8080/
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 05 Oct 2016 14:15:24 GMT
< Content-Length: 13
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
Hello, World!

Would goroutines write into same line, when then write log at same time?

Excuse me,I want to use combinedLoggingHandler to record users http request.
In httpserver goroutine is used to process the request, and function ServeHTTP is called in goroutine.
So the question is when 2 goroutines write log at same time, would they write into same line?
If so, how to prevent?

Skip handler or only use handler on subrouter

Would be useful to have examples for:

  1. Skipping handlers, e.g. avoid logging certain requests when there's a LoggingHandler configured
  2. Only use a handler on a subrouter (this could be an alternative to 1 but is also useful on its own)

Logging Handlers remove Hijack method from implementations of ResponseWriter breaking websockets

I implemented something very similar to your logging handlers a while back before I knew that this package existed. Wanting to log all of my requests, I wrapped my router in my logging handler:

r := mux.NewRouter()
// ...
http.ListenAndServe(httpAddress, LoggingHandler{r}) // my version is a bit different

Seemed to work well, but whoops! My web sockets couldn't hijack the connection anymore. I came up with a fix for it that I can apply to this package if interested.

ProxyHeaders breaks cleanPath redirects

I encountered an issue today, where ProxyHeaders middleware causes mux to send invalid redirects when it tries to clean the path.

Suppose you have a reverse proxy that sends the X-Forwarded-Proto: https header, and your user agent sends a request line containing only an absolute path, with no hostname (or scheme). I believe this is legal according to RFC2616, and it appears to be how Varnish and HAProxy work.

This will result in ProxyHeaders setting the scheme on the request's URL. However, the hostname will still be empty.

Now, everything is fine until/unless you are using gorilla/mux and it tries to clean the path. It will call url.String() to get the value for the Location header in the redirect.

net/url.URL.String() will then happily concatenate the non-empty scheme, empty host, and non-empty path, resulting in a header like Location: https:///foo/bar/.

ProxyHeaders handling of X-Forwarded-For is Naive

Currently, the handling of the X-Forwarded-For header in the ProxyHeaders middleware is overly simplistic and naive. It simply chooses the leftmost value.

However, this opens up two potential issues.

  1. It is valid and reasonable usage for the X-Forwarded-For chain to include client-side proxy values, in which the leftmost value could be a local ip address. This will nearly never be the desired value for consumers of this package.

An example of this might be:

X-Forwarded-For: 192.168.1.23, 42.34.21.211

Where 192.168.1.23 represents a private, client-side IP address, and 42.34.21.211 represents a client-side http proxy server. In most real world cases, the desired value for the "real" IP would be the proxy server, 42.34.21.211.

  1. For use of this package directly behind an AWS ELB, the AWS ELB does not purge the previously set X-Forwarded-For value. This is actually a good thing, because some requests may require passes through multiple ELB layers and we need a way to see the correct original address. However, that opens up the possibility for users to include their own X-Forwarded-For header that provides a fabricated IP source as the leftmost value.

It appears that these issues are known and the suggestion is to use this only behind a reverse proxy which purges and resets the X-Forwarded-For header. This cripples the application of this middleware in real world usage. For example, it cannot be reliably or safely used directly behind an Amazon ELB. In the case of nginx, it requires a specific configuration to be safely used. Further, many users of this library are likely to use this middleware in an environment where the X-Forwared-For header may contain untrusted values, without understanding the specific vulnerabilities that this opens up.

I would suggest a more comprehensive handling of the X-Forwarded-For header that is similar to the nginx implementation of set_real_ip_from. That is, that there should be a defined set of trusted CIDRs, and that the real address is the last address in the chain that is not within the list of trusted CIDRs. If all IP values fall within the list of trusted CIDRs, then the leftmost value would be used.

I would further suggest a default set of trusted CIDR values based on the IETF private address spaces, which is a more secure starting point and would require specific changes to introduce vulnerabilities.

Given that implementation, the limitation on the secure application of this code is simply that it has to exist behind a trusted proxy that properly sets or appends to the X-Forwarded-For header.

Before I work on code for such an implementation, I would like to know if the maintainers and community are open to such a change.

CORSHandler: returns Method not allowed for OPTIONS

For OPTIONS request the CORS middleware passes the request to the next middleware which always returns '405' status.

this fixes it:

@@ -112,6 +114,10 @@ func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {

        w.Header().Set(corsAllowOriginHeader, origin)

+       if r.Method == corsOptionMethod {
+               return
+       }
+
        ch.h.ServeHTTP(w, r)
 }

Is this a bug or am I doing something wrong?

Cache Control & Static File Server

Hi Gorilla Team :) Firstly thank you for all of the great packages!

I've been struggling to find a package that has sensible cache control headers for static files. Would something like that be a useful handler? My first thought was that it would feel right living next to the logging and compression handlers.

There are pretty sensible defaults located at github.com/h5bp/server-configs-nginx

Example:

package main

import (
    "fmt"
    "net/http"
    "os"

    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", HomeHandler)
    r.PathPrefix("/").Handler(handlers.StaticCache(http.FileServer(http.Dir("./static/"))))
    http.ListenAndServe(os.Getenv("HOST")+":"+os.Getenv("PORT"), r)
}

func HomeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World")
}

Access-Control-Expose-Headers not added to preflight

The Access-Control-Expose-Headers header is added to the GET request (or any non-OPTIONS request) following a preflight, but it is excluded from the preflight. I wasn't able to find hard documentation stating where this header should go, but I can attest that I can't access a custom header in JavaScript unless I also add the Access-Control-Expose-Headers header to the preflight response in the latest Chrome.

https://github.com/gorilla/handlers/blob/master/cors.go#L100

CompressHandler: Investigate Broken Build Against tip

Build is failing against tip:

--- FAIL: TestCompressHandlerNoCompression (0.00s)
    compress_test.go:37: wrong content type, got "text/plain; charset=utf-8" want ""
    if ct := w.HeaderMap.Get("Content-Type"); ct != "" {
        t.Errorf("wrong content type, got %q want %q", ct, "")
    }

Using handler.CompressHandler with mux.NotFoundHandler

Hey,

I seem to be getting errors when using a CompressHandler in conjunction with a NotFoundHandler. In the following example my 404's don't work at all and the browser's just dumping a "This site can’t be reached" error to the screen. No error messages or stack traces coming from Go either :/

If I comment out r.NotFoundHandler or h2 := handlers.CompressHandler(h1) then it works.

package main

import (
    "fmt"
    "net/http"
    "os"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()

    r.HandleFunc("/", IndexHandler).Methods("GET")
    r.HandleFunc("/test", TestHandler).Methods("GET")
    r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)

    h1 := handlers.CombinedLoggingHandler(os.Stdout, r)
    h2 := handlers.CompressHandler(h1)

    http.ListenAndServe("localhost:"+os.Getenv("PORT"), h2)
}

func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusNotFound)
    fmt.Fprintf(w, "404 - Not Found")
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}

func TestHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Looks good!")
}

Logging Handlers and Recovery handlers do not support structured JSON output

My team manages hundreds of micro services on thousands on nodes. We monitor everything and send our logs to a centralized logging solution, where we can query and analyze the logs.
The apache log format used by the LoggingHandler might be fine for most use cases but is definitely no ok for our case. That is why I would really appreciate it if there was a JSONLoggingHandler or StructuredLoggingHandler, which logs the same information but as a single-line JSON document. This would allow me to easily query the data without having to parse the logs and convert them to JSON.

CompressHandler: Write on hijacked connection error

If the ResponseWriter I pass to handlers.CompressHandler support http.Hijacker gets hijacked, I'll often see this error come out of my server:

2015/08/25 09:20:41 server.go:1934: http: response.Write on hijacked connection

I believe this is caused by the deferred Close calls on the gzip/flat Writer's. The documentation for both says that calling Close will flush any pending data, which might generate calls to Write. I believe the fix is to set a flag if Hijack is called on the connection, and only call Call on the gzip/flat Writer if the connection was not hijacked.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.