From 7796ff0f690b96f49d310cbd1817dedcf1a40fad Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Wed, 5 Aug 2015 11:33:51 -0600 Subject: [PATCH 01/12] core: Disable TLS for http sites (again) Fixes bug introduced in 0ac8bf5 - Also note that setup functions no longer have access to server port. Will need to fix later. --- config/config.go | 5 +++++ config/setup/fastcgi.go | 2 +- config/setup/tls.go | 6 ------ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/config/config.go b/config/config.go index 3037a267..82a29585 100644 --- a/config/config.go +++ b/config/config.go @@ -57,6 +57,11 @@ func Load(filename string, input io.Reader) (Group, error) { if config.Port == "" { config.Port = Port } + if config.Port == "http" { + config.TLS.Enabled = false + log.Printf("Warning: TLS disabled for %s://%s. To force TLS over the plaintext HTTP port, "+ + "specify port 80 explicitly (https://%s:80).", config.Port, config.Host, config.Host) + } if i == 0 { sharedConfig.Startup = []func() error{} sharedConfig.Shutdown = []func() error{} diff --git a/config/setup/fastcgi.go b/config/setup/fastcgi.go index a2a7e879..ab21ef1f 100644 --- a/config/setup/fastcgi.go +++ b/config/setup/fastcgi.go @@ -31,7 +31,7 @@ func FastCGI(c *Controller) (middleware.Middleware, error) { SoftwareName: c.AppName, SoftwareVersion: c.AppVersion, ServerName: c.Host, - ServerPort: c.Port, + ServerPort: c.Port, // BUG: This is not known until the server blocks are split up... } }, nil } diff --git a/config/setup/tls.go b/config/setup/tls.go index 36ecac05..431409f4 100644 --- a/config/setup/tls.go +++ b/config/setup/tls.go @@ -2,7 +2,6 @@ package setup import ( "crypto/tls" - "log" "strings" "github.com/mholt/caddy/middleware" @@ -10,11 +9,6 @@ import ( func TLS(c *Controller) (middleware.Middleware, error) { c.TLS.Enabled = true - if c.Port == "http" { - c.TLS.Enabled = false - log.Printf("Warning: TLS disabled for %s://%s. To force TLS over the plaintext HTTP port, "+ - "specify port 80 explicitly (https://%s:80).", c.Port, c.Host, c.Host) - } for c.Next() { if !c.NextArg() { From a2be7b45485ee9fdafd0609a90e87b434fcc8538 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Wed, 5 Aug 2015 13:26:12 -0600 Subject: [PATCH 02/12] Bumped version to 0.7.5 --- .gitignore | 2 ++ app/app.go | 2 +- dist/CHANGES.txt | 7 ++++++- dist/README.txt | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 3f87b8fb..0dd26ce5 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ access.log /*.conf Caddyfile + +og_static/ \ No newline at end of file diff --git a/app/app.go b/app/app.go index e73f95b4..b006d294 100644 --- a/app/app.go +++ b/app/app.go @@ -20,7 +20,7 @@ const ( Name = "Caddy" // Version is the program version - Version = "0.7.4" + Version = "0.7.5" ) var ( diff --git a/dist/CHANGES.txt b/dist/CHANGES.txt index 34faa66a..dced4bd4 100644 --- a/dist/CHANGES.txt +++ b/dist/CHANGES.txt @@ -1,9 +1,14 @@ CHANGES - +0.7.5 (August 5, 2015) +- core: All listeners bind to 0.0.0.0 unless 'bind' directive is used - fastcgi: Set HTTPS env variable if connection is secure +- log: Output to system log (except Windows) +- markdown: Added dev command to disable caching during development - markdown: Fixed error reporting during initial site generation - markdown: Fixed crash if path does not exist when server starts +- markdown: Fixed site generation and link indexing when files change +- templates: Added .NowDate for use in date-related functions - Several bug fixes related to startup and shutdown functions diff --git a/dist/README.txt b/dist/README.txt index 4a0713b8..2a3cbfc0 100644 --- a/dist/README.txt +++ b/dist/README.txt @@ -1,4 +1,4 @@ -CADDY 0.7.4 +CADDY 0.7.5 Website https://caddyserver.com From bb072faeee39164f987ff6463ce0ef0e65c6f955 Mon Sep 17 00:00:00 2001 From: Karthic Rao Date: Sat, 8 Aug 2015 00:56:59 +0530 Subject: [PATCH 03/12] Initial test for middleware/middleware.go --- middleware/middleware_test.go | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 middleware/middleware_test.go diff --git a/middleware/middleware_test.go b/middleware/middleware_test.go new file mode 100644 index 00000000..e5b238e6 --- /dev/null +++ b/middleware/middleware_test.go @@ -0,0 +1,41 @@ +package middleware + +import ( + "net/http" + "testing" +) + +func TestIndexfile(t *testing.T) { + tests := []struct { + rootDir http.FileSystem + fpath string + indexFiles []string + shouldErr bool + expectedFilePath string //retun value + expectedBoolValue bool //return value + }{ + { + http.Dir("./templates/testdata"), "/images/", []string{"img.htm"}, + false, + "/images/img.htm", true, + }, + } + for i, test := range tests { + actualFilePath, actualBoolValue := IndexFile(test.rootDir, test.fpath, test.indexFiles) + if actualBoolValue == true && test.shouldErr { + t.Errorf("Test %d didn't error, but it should have", i) + } else if actualBoolValue != true && !test.shouldErr { + t.Errorf("Test %d errored, but it shouldn't have; got %s", i, "Please Add a / at the end of fpath or the indexFiles doesnt exist") + } + if actualFilePath != test.expectedFilePath { + t.Fatalf("Test %d expected returned filepath to be %s, but got %s ", + i, test.expectedFilePath, actualFilePath) + + } + if actualBoolValue != test.expectedBoolValue { + t.Fatalf("Test %d expected returned bool value to be %v, but got %v ", + i, test.expectedBoolValue, actualBoolValue) + + } + } +} From 60b6c0c03d689b861df9174221be04df99102c2b Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Wed, 5 Aug 2015 16:32:34 -0600 Subject: [PATCH 04/12] Add link to joshix/caddy in readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c17b3d0a..76645389 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ Caddy is available as a Docker container from any of these sources: - [abiosoft/caddy](https://registry.hub.docker.com/u/abiosoft/caddy/) - [darron/caddy](https://registry.hub.docker.com/u/darron/caddy/) +- [joshix/caddy](https://registry.hub.docker.com/u/joshix/caddy/) - [jumanjiman/caddy](https://registry.hub.docker.com/u/jumanjiman/caddy/) - [zenithar/nano-caddy](https://registry.hub.docker.com/u/zenithar/nano-caddy/) From 53c4797606e5ded3ddc1437ca164d0c60fc74a12 Mon Sep 17 00:00:00 2001 From: Karthic Rao Date: Tue, 11 Aug 2015 22:02:13 +0530 Subject: [PATCH 05/12] Initial setup of test for recorder.go of middleware package --- middleware/recorder_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 middleware/recorder_test.go diff --git a/middleware/recorder_test.go b/middleware/recorder_test.go new file mode 100644 index 00000000..5a2fa10c --- /dev/null +++ b/middleware/recorder_test.go @@ -0,0 +1,19 @@ +package middleware + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" +) + +func TestNewResponseRecorder(t *testing.T) { + w := httptest.NewRecorder() + recordRequest := NewResponseRecorder(w) + if !reflect.DeepEqual(recordRequest.ResponseWriter, w) { + t.Fatalf("Expected Response writer in the Recording to be same as the one sent") + } + if recordRequest.status != http.StatusOK { + t.Fatalf("Expected recorded status to be http.StatusOK") + } +} From 4704625e3a70b261fd40dc5a66d35b74876bc5ac Mon Sep 17 00:00:00 2001 From: Karthic Rao Date: Fri, 14 Aug 2015 09:59:22 +0530 Subject: [PATCH 06/12] Complete test coverage for middleware/recorder.go --- middleware/recorder_test.go | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/middleware/recorder_test.go b/middleware/recorder_test.go index 5a2fa10c..9d4e5b83 100644 --- a/middleware/recorder_test.go +++ b/middleware/recorder_test.go @@ -3,17 +3,38 @@ package middleware import ( "net/http" "net/http/httptest" - "reflect" "testing" ) func TestNewResponseRecorder(t *testing.T) { w := httptest.NewRecorder() recordRequest := NewResponseRecorder(w) - if !reflect.DeepEqual(recordRequest.ResponseWriter, w) { - t.Fatalf("Expected Response writer in the Recording to be same as the one sent") + if !(recordRequest.ResponseWriter == w) { + t.Fatalf("Expected Response writer in the Recording to be same as the one sent\n") } if recordRequest.status != http.StatusOK { - t.Fatalf("Expected recorded status to be http.StatusOK") + t.Fatalf("Expected recorded status to be http.StatusOK (%d) , but found %d\n ", recordRequest.status) + } +} +func TestWriteHeader(t *testing.T) { + w := httptest.NewRecorder() + recordRequest := NewResponseRecorder(w) + recordRequest.WriteHeader(401) + if w.Code != 401 || recordRequest.status != 401 { + t.Fatalf("Expected Response status to be set to 401, but found %d\n", recordRequest.status) + } +} + +func TestWrite(t *testing.T) { + w := httptest.NewRecorder() + responseTestString := "test" + recordRequest := NewResponseRecorder(w) + buf := []byte(responseTestString) + recordRequest.Write(buf) + if recordRequest.size != len(buf) { + t.Fatalf("Expected the bytes written counter to be %d, but instead found %d\n", len(buf), recordRequest.size) + } + if w.Body.String() != responseTestString { + t.Fatalf("Expected Response Body to be %s , but found %s\n", w.Body.String()) } } From 414b47d653254f15102a6cb92efaedfa1745d320 Mon Sep 17 00:00:00 2001 From: Abdulelah Alfuntukh Date: Tue, 18 Aug 2015 02:29:52 +0300 Subject: [PATCH 07/12] adds json option for the browse middleware --- middleware/browse/browse.go | 46 +++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/middleware/browse/browse.go b/middleware/browse/browse.go index 6868be88..341f86a3 100644 --- a/middleware/browse/browse.go +++ b/middleware/browse/browse.go @@ -4,12 +4,14 @@ package browse import ( "bytes" + "encoding/json" "errors" "net/http" "net/url" "os" "path" "sort" + "strconv" "strings" "text/template" "time" @@ -185,7 +187,6 @@ func directoryListing(files []os.FileInfo, r *http.Request, canGoUp bool, root s // ServeHTTP implements the middleware.Handler interface. func (b Browse) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { filename := b.Root + r.URL.Path - info, err := os.Stat(filename) if err != nil { return b.Next.ServeHTTP(w, r) @@ -264,12 +265,47 @@ func (b Browse) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { listing.applySort() var buf bytes.Buffer - err = bc.Template.Execute(&buf, listing) - if err != nil { - return http.StatusInternalServerError, err + // check if we should provide json + acceptHeader := strings.Join(r.Header["Accept"], ",") + if strings.Contains(strings.ToLower(acceptHeader), "application/json") { + var marsh []byte + // check if we are limited + if limitQuery := r.URL.Query().Get("limit"); limitQuery != "" { + limit, err := strconv.Atoi(limitQuery) + if err != nil { // if the 'limit' query can't be interpreted as a number, return err + return http.StatusBadRequest, err + } + // if `limit` is equal or less than len(listing.Items) and bigger than 0, list them + if limit <= len(listing.Items) && limit > 0 { + marsh, err = json.Marshal(listing.Items[:limit]) + } else { // if the 'limit' query is empty, or has the wrong value, list everything + marsh, err = json.Marshal(listing.Items) + } + if err != nil { + return http.StatusInternalServerError, err + } + } else { // there's no 'limit' query, list them all + marsh, err = json.Marshal(listing.Items) + if err != nil { + return http.StatusInternalServerError, err + } + } + + // write the marshaled json to buf + if _, err = buf.Write(marsh); err != nil { + return http.StatusInternalServerError, err + } + w.Header().Set("Content-Type", "application/json; charset=utf-8") + + } else { // there's no json query, browse normally + err = bc.Template.Execute(&buf, listing) + if err != nil { + return http.StatusInternalServerError, err + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + } - w.Header().Set("Content-Type", "text/html; charset=utf-8") buf.WriteTo(w) return http.StatusOK, nil From b9d3e7721ed304809b74bfae6a49d75cc219f8ae Mon Sep 17 00:00:00 2001 From: pyed Date: Thu, 27 Aug 2015 17:57:59 +0300 Subject: [PATCH 08/12] Fixing my comment the old comment might throw the source-reader off, my bad. --- middleware/browse/browse.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middleware/browse/browse.go b/middleware/browse/browse.go index 341f86a3..8036896f 100644 --- a/middleware/browse/browse.go +++ b/middleware/browse/browse.go @@ -297,7 +297,7 @@ func (b Browse) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { } w.Header().Set("Content-Type", "application/json; charset=utf-8") - } else { // there's no json query, browse normally + } else { // there's no 'application/json' in the 'Accept' header, browse normally err = bc.Template.Execute(&buf, listing) if err != nil { return http.StatusInternalServerError, err From 444f9e40d5ce8a3fa71566d1a9844d7bed0bc593 Mon Sep 17 00:00:00 2001 From: Karthic Rao Date: Thu, 27 Aug 2015 23:36:32 +0530 Subject: [PATCH 09/12] initial test for replacer --- middleware/replacer_test.go | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 middleware/replacer_test.go diff --git a/middleware/replacer_test.go b/middleware/replacer_test.go new file mode 100644 index 00000000..ad8a9489 --- /dev/null +++ b/middleware/replacer_test.go @@ -0,0 +1,38 @@ +package middleware + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func TestNewReplacer(t *testing.T) { + w := httptest.NewRecorder() + recordRequest := NewResponseRecorder(w) + userJson := `{"username": "dennis"}` + + reader := strings.NewReader(userJson) //Convert string to reader + + request, err := http.NewRequest("POST", "http://caddyserver.com", reader) //Create request with JSON body + if err != nil { + t.Fatalf("Request Formation Failed \n") + } + replaceValues := NewReplacer(request, recordRequest, "") + + switch v := replaceValues.(type) { + case replacer: + if v.replacements["{host}"] != "caddyserver.com" { + t.Errorf("Expected host to be caddyserver.com") + } + if v.replacements["{method}"] != "POST" { + t.Errorf("Expected request method to be POST") + } + if v.replacements["{status}"] != "200" { + t.Errorf("Expected status to be 200") + } + + default: + t.Fatalf("Return Value from New Replacer expected pass type assertion into a replacer type \n") + } +} From 730269743fc5a03df419afd0e187c109747d7fd3 Mon Sep 17 00:00:00 2001 From: Karthic Rao Date: Sat, 29 Aug 2015 08:04:01 +0530 Subject: [PATCH 10/12] Json response initial test for browse.go --- middleware/browse/browse_test.go | 93 +++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/middleware/browse/browse_test.go b/middleware/browse/browse_test.go index b0ff28db..13894a8d 100644 --- a/middleware/browse/browse_test.go +++ b/middleware/browse/browse_test.go @@ -1,14 +1,17 @@ package browse import ( + //"bytes" + "encoding/json" + "github.com/mholt/caddy/middleware" "net/http" "net/http/httptest" + "net/url" + "os" "sort" "testing" "text/template" "time" - - "github.com/mholt/caddy/middleware" ) // "sort" package has "IsSorted" function, but no "IsReversed"; @@ -154,4 +157,90 @@ func TestBrowseTemplate(t *testing.T) { if respBody != expectedBody { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } + +} + +func TestBrowseJson(t *testing.T) { + + b := Browse{ + Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { + t.Fatalf("Next shouldn't be called") + return 0, nil + }), + Root: "./testdata", + Configs: []Config{ + Config{ + PathScope: "/photos", + }, + }, + } + + req, err := http.NewRequest("GET", "/photos/", nil) + if err != nil { + t.Fatalf("Test: Could not create HTTP request: %v", err) + } + req.Header.Set("Accept", "application/json") + rec := httptest.NewRecorder() + + b.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Wrong status, expected %d, got %d", http.StatusOK, rec.Code) + } + if rec.HeaderMap.Get("Content-Type") != "application/json; charset=utf-8" { + t.Fatalf("Expected Content type to be application/json; charset=utf-8, but got %s ", rec.HeaderMap.Get("Content-Type")) + } + + actualJsonResponseString := rec.Body.String() + //t.Logf("json response body: %s\n", respBody) + //generating the listing to compare it with the response body + file, err := os.Open(b.Root + req.URL.Path) + if err != nil { + if os.IsPermission(err) { + t.Fatalf("Os Permission Error") + + } + + } + defer file.Close() + + files, err := file.Readdir(-1) + if err != nil { + t.Fatalf("Unable to Read Contents of the directory") + } + var fileinfos []FileInfo + for _, f := range files { + name := f.Name() + + if f.IsDir() { + name += "/" + } + + url := url.URL{Path: name} + + fileinfos = append(fileinfos, FileInfo{ + IsDir: f.IsDir(), + Name: f.Name(), + Size: f.Size(), + URL: url.String(), + ModTime: f.ModTime(), + Mode: f.Mode(), + }) + } + listing := Listing{ + Items: fileinfos, + } + listing.Sort = "name" + listing.Order = "asc" + listing.applySort() + + //var buf bytes.Buffer + marsh, err := json.Marshal(listing.Items) + if err != nil { + t.Fatalf("Unable to Marshal the listing ") + } + //t.Logf("json value: %s\n", string(marsh)) + expectedJsonString := string(marsh) + if actualJsonResponseString != expectedJsonString { + t.Errorf("Json response string doesnt match the expected Json response ") + } } From e3cea042d63a7f4eb8fb7151c8634b812eea917a Mon Sep 17 00:00:00 2001 From: karthic rao Date: Sun, 30 Aug 2015 19:00:35 +0530 Subject: [PATCH 11/12] Left over comments removed Redundant comments in the code removed --- middleware/browse/browse_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/middleware/browse/browse_test.go b/middleware/browse/browse_test.go index 13894a8d..9f91f34e 100644 --- a/middleware/browse/browse_test.go +++ b/middleware/browse/browse_test.go @@ -1,8 +1,7 @@ package browse import ( - //"bytes" - "encoding/json" + "encoding/json" "github.com/mholt/caddy/middleware" "net/http" "net/http/httptest" @@ -191,7 +190,7 @@ func TestBrowseJson(t *testing.T) { } actualJsonResponseString := rec.Body.String() - //t.Logf("json response body: %s\n", respBody) + //generating the listing to compare it with the response body file, err := os.Open(b.Root + req.URL.Path) if err != nil { @@ -233,12 +232,10 @@ func TestBrowseJson(t *testing.T) { listing.Order = "asc" listing.applySort() - //var buf bytes.Buffer marsh, err := json.Marshal(listing.Items) if err != nil { t.Fatalf("Unable to Marshal the listing ") } - //t.Logf("json value: %s\n", string(marsh)) expectedJsonString := string(marsh) if actualJsonResponseString != expectedJsonString { t.Errorf("Json response string doesnt match the expected Json response ") From d79d2611ca592068e5fcc85eecbca5c1a3a1fbae Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Sun, 30 Aug 2015 10:55:30 -0600 Subject: [PATCH 12/12] Mention setcap in readme so it's more prominent --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 76645389..44fd023b 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ By default, Caddy serves the current directory at [localhost:2015](http://localh Caddy accepts some flags from the command line. Run `caddy -h` to view the help for flags. You can also pipe a Caddyfile into the caddy command. +**Running as root:** We advise against this; use setcap instead, like so: `setcap cap_net_bind_service=+ep ./caddy` This will allow you to listen on ports below 1024 (like 80 and 443). #### Docker Container