Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send a 405 Method Not Allowed error when POST to a static asset #1818

Merged
merged 9 commits into from Mar 20, 2019
@@ -379,6 +379,37 @@ jobs:
path: cypress/results
- announce_failure

# `integration_tests_api` runs integration tests using Cypress. https://www.cypress.io/
integration_tests_api:
executor: mymove_medium
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: true
- restore_cache:
keys:
- go-pkg-dep-sources-{{ checksum "Gopkg.lock" }}
- restore_cache:
keys:
- mymove-vendor-{{ checksum "Gopkg.lock" }}
- restore_cache:
keys:
- v1-cache-yarn-v2-{{ checksum "yarn.lock" }}
- restore_cache:
keys:
- v1-mymove-node-modules-{{ checksum "yarn.lock" }}
- e2e_tests:
spec: 'cypress/integration/api/**/*'
- store_artifacts:
path: cypress/videos
destination: videos
- store_artifacts:
path: cypress/screenshots
destination: screenshots
- store_test_results:
path: cypress/results
- announce_failure

# `server_test` runs the server side Go tests
server_test:
executor: mymove_and_postgres_medium
@@ -803,6 +834,16 @@ workflows:
# branches:
# ignore: placeholder_branch_name

- integration_tests_api:
requires:
- pre_deps_golang
- pre_deps_yarn
- acceptance_tests_local
# if testing on experimental, you can disable these tests by using the commented block below.
# filters:
# branches:
# ignore: placeholder_branch_name

- client_test:
requires:
- pre_deps_yarn
@@ -874,6 +915,7 @@ workflows:
- integration_tests_mymove
- integration_tests_office
- integration_tests_tsp
- integration_tests_api
filters:
branches:
only: master
@@ -154,6 +154,18 @@ func httpsComplianceMiddleware(inner http.Handler) http.Handler {
return http.HandlerFunc(mw)
}

func validMethodForStaticMiddleware(inner http.Handler) http.Handler {
mw := func(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" && r.Method != "HEAD" {
http.Error(w, http.StatusText(405), http.StatusMethodNotAllowed)
return
}
inner.ServeHTTP(w, r)
return
}
return http.HandlerFunc(mw)
}

func securityHeadersMiddleware(inner http.Handler) http.Handler {
zap.L().Debug("securityHeadersMiddleware installed")
mw := func(w http.ResponseWriter, r *http.Request) {
@@ -1053,16 +1065,22 @@ func main() {
)
})

staticMux := goji.SubMux()
staticMux.Use(validMethodForStaticMiddleware)
staticMux.Handle(pat.Get("/*"), clientHandler)
// Needed to serve static paths (like favicon)
staticMux.Handle(pat.Get(""), clientHandler)

// Allow public content through without any auth or app checks
site.Handle(pat.Get("/static/*"), clientHandler)
site.Handle(pat.Get("/downloads/*"), clientHandler)
site.Handle(pat.Get("/favicon.ico"), clientHandler)
site.Handle(pat.New("/static/*"), staticMux)
site.Handle(pat.New("/downloads/*"), staticMux)
site.Handle(pat.New("/favicon.ico"), staticMux)

// Explicitly disable swagger.json route
site.Handle(pat.Get("/swagger.json"), http.NotFoundHandler())
if v.GetBool(serveSwaggerUIFlag) {
logger.Info("Swagger UI static file serving is enabled")
site.Handle(pat.Get("/swagger-ui/*"), clientHandler)
site.Handle(pat.Get("/swagger-ui/*"), staticMux)

This comment has been minimized.

Copy link
@chrisgilmerproj

chrisgilmerproj Mar 20, 2019

Contributor

nice find!

} else {
site.Handle(pat.Get("/swagger-ui/*"), http.NotFoundHandler())
}
@@ -4,6 +4,8 @@ import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
@@ -162,3 +164,28 @@ func (suite *webServerSuite) TestDatabase() {
_, err := initDatabase(suite.viper, suite.logger)
suite.Nil(err)
}

func (suite *webServerSuite) TestStaticReqMethodMiddleware() {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
middleware := validMethodForStaticMiddleware(handler)

// For a GET request, we should get a 200
rr := httptest.NewRecorder()
req := httptest.NewRequest("GET", "http://mil.example.com/static/something", nil)
middleware.ServeHTTP(rr, req)
suite.Equal(http.StatusOK, rr.Code, "handler returned wrong status code")

// For a HEAD request, we should also get a 200
rr = httptest.NewRecorder()
req = httptest.NewRequest("HEAD", "http://mil.example.com/static/something", nil)
middleware.ServeHTTP(rr, req)
suite.Equal(http.StatusOK, rr.Code, "handler returned wrong status code")

// For a POST request, we should get a 405 response
rr = httptest.NewRecorder()
req = httptest.NewRequest("POST", "http://mil.example.com/static/something", nil)
middleware.ServeHTTP(rr, req)
suite.Equal(http.StatusMethodNotAllowed, rr.Code, "handler returned wrong status code")
}
@@ -0,0 +1,32 @@
/* global cy, before */

describe('static file hosting', () => {
before(() => {
cy.setupBaseUrl('milmove');
});

it('returns the correct content type', () => {
cy
.request('/swagger-ui/internal.html')
.its('headers')
.its('content-type')
.should('include', 'text/html');
});

it('returns the correct status', () => {
cy
.request('/swagger-ui/internal.html')
.its('status')
.should('equal', 200);
});

it('rejects POST requests', () => {
let req = cy.request({
method: 'POST',
url: '/swagger-ui/internal.html',
failOnStatusCode: false,
});

req.its('status').should('equal', 405);
});
});
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.