-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
57 changed files
with
537 additions
and
17,343 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
FROM golang:1.6-onbuild | ||
FROM golang:1.8-onbuild | ||
|
||
RUN mkdir /data | ||
VOLUME ["/data"] | ||
WORKDIR /data | ||
EXPOSE 5000 | ||
ENTRYPOINT ["app"] | ||
ENTRYPOINT ["app"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"regexp" | ||
"strings" | ||
) | ||
|
||
var ( | ||
parensExpr = regexp.MustCompile("([^\\\\])\\(([^)]+)\\)") | ||
questionExpr = regexp.MustCompile("\\?([^(])") | ||
) | ||
|
||
func CompileExtGlob(extglob string) (*regexp.Regexp, error) { | ||
tmp := extglob | ||
tmp = strings.Replace(tmp, ".", "\\.", -1) | ||
tmp = strings.Replace(tmp, "**", ".🐷", -1) | ||
tmp = strings.Replace(tmp, "*", fmt.Sprintf("[^%c]*", os.PathSeparator), -1) | ||
tmp = questionExpr.ReplaceAllString(tmp, fmt.Sprintf("[^%c]$1", os.PathSeparator)) | ||
tmp = parensExpr.ReplaceAllString(tmp, "($2)$1") | ||
tmp = strings.Replace(tmp, ")@", ")", -1) | ||
tmp = strings.Replace(tmp, ".🐷", ".*", -1) | ||
return regexp.Compile("^" + tmp + "$") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
type TableEntry struct { | ||
Glob string | ||
Matches []string | ||
NonMatches []string | ||
} | ||
|
||
var ( | ||
table = []TableEntry{ | ||
{ | ||
Glob: "asdf/*.jpg", | ||
Matches: []string{"asdf/asdf.jpg", "asdf/asdf_asdf.jpg", "asdf/.jpg"}, | ||
NonMatches: []string{"asdf/asdf/asdf.jpg", "xxxasdf/asdf.jpgxxx"}, | ||
}, | ||
{ | ||
Glob: "asdf/**.jpg", | ||
Matches: []string{"asdf/asdf.jpg", "asdf/asdf_asdf.jpg", "asdf/asdf/asdf.jpg", "asdf/asdf/asdf/asdf/asdf.jpg"}, | ||
NonMatches: []string{"/asdf/asdf.jpg", "asdff/asdf.jpg", "xxxasdf/asdf.jpgxxx"}, | ||
}, | ||
{ | ||
Glob: "asdf/*.@(jpg|jpeg)", | ||
Matches: []string{"asdf/asdf.jpg", "asdf/asdf_asdf.jpeg"}, | ||
NonMatches: []string{"/asdf/asdf.jpg", "asdff/asdf.jpg"}, | ||
}, | ||
{ | ||
Glob: "**/*.js", | ||
Matches: []string{"asdf/asdf.js", "asdf/asdf/asdfasdf_asdf.js", "/asdf/asdf.js", "/asdf/aasdf-asdf.2.1.4.js"}, | ||
NonMatches: []string{"/asdf/asdf.jpg", "asdf.js"}, | ||
}, | ||
} | ||
) | ||
|
||
func Test_CompileExtGlob(t *testing.T) { | ||
for _, entry := range table { | ||
r, err := CompileExtGlob(entry.Glob) | ||
if err != nil { | ||
t.Fatalf("Couldn’t compile glob %s: %s", entry.Glob, err) | ||
} | ||
for _, match := range entry.Matches { | ||
if !r.MatchString(match) { | ||
t.Fatalf("%s didn’t match %s", entry.Glob, match) | ||
} | ||
} | ||
for _, nonmatch := range entry.NonMatches { | ||
if r.MatchString(nonmatch) { | ||
t.Fatalf("%s matched %s", entry.Glob, nonmatch) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
type FirebaseManifest struct { | ||
Public string `json:"public"` | ||
Redirects []struct { | ||
Source string `json:"source"` | ||
Destination string `json:"destination"` | ||
Type int `json:"type,omitempty"` | ||
} `json:"redirects"` | ||
Rewrites []struct { | ||
Source string `json:"source"` | ||
Destination string `json:"destination"` | ||
} `json:"rewrites"` | ||
Headers []struct { | ||
Source string `json:"source"` | ||
Headers []struct { | ||
Key string `json:"key"` | ||
Value string `json:"value"` | ||
} `json:"headers"` | ||
} `json:"headers"` | ||
Hosting *FirebaseManifest `json:"Hosting"` | ||
} | ||
|
||
func (mf FirebaseManifest) processRedirects(w http.ResponseWriter, r *http.Request) (bool, error) { | ||
for _, redirect := range mf.Redirects { | ||
pattern, err := CompileExtGlob(redirect.Source) | ||
if err != nil { | ||
return false, fmt.Errorf("Invalid redirect extglob %s: %s", redirect.Source, err) | ||
} | ||
if pattern.MatchString(r.URL.Path) { | ||
http.Redirect(w, r, redirect.Destination, redirect.Type) | ||
return true, nil | ||
} | ||
} | ||
if mf.Hosting != nil { | ||
return mf.Hosting.processRedirects(w, r) | ||
} | ||
return false, nil | ||
} | ||
|
||
func (mf FirebaseManifest) processRewrites(r *http.Request) error { | ||
for _, rewrite := range mf.Rewrites { | ||
pattern, err := CompileExtGlob(rewrite.Source) | ||
if err != nil { | ||
return fmt.Errorf("Invalid rewrite extglob %s: %s", rewrite.Source, err) | ||
} | ||
if pattern.MatchString(r.URL.Path) { | ||
r.URL.Path = strings.TrimSuffix(rewrite.Destination, "index.html") | ||
return nil | ||
} | ||
} | ||
if mf.Hosting != nil { | ||
return mf.Hosting.processRewrites(r) | ||
} | ||
return nil | ||
} | ||
|
||
func (mf FirebaseManifest) processHosting(w http.ResponseWriter, r *http.Request) error { | ||
for _, headerSet := range mf.Headers { | ||
pattern, err := CompileExtGlob(headerSet.Source) | ||
if err != nil { | ||
return fmt.Errorf("Invalid hosting.header extglob %s: %s", headerSet.Source, err) | ||
} | ||
if pattern.MatchString(r.URL.Path) { | ||
for _, header := range headerSet.Headers { | ||
w.Header().Set(header.Key, header.Value) | ||
} | ||
} | ||
} | ||
if mf.Hosting != nil { | ||
return mf.Hosting.processHosting(w, r) | ||
} | ||
return nil | ||
} | ||
|
||
func processWithConfig(w http.ResponseWriter, r *http.Request, config string) string { | ||
dir := "." | ||
mf, err := readManifest(config) | ||
if err != nil { | ||
log.Printf("Could read Firebase file %s: %s", config, err) | ||
return dir | ||
} | ||
if mf.Public != "" { | ||
dir = mf.Public | ||
} | ||
|
||
done, err := mf.processRedirects(w, r) | ||
if err != nil { | ||
log.Printf("Processing redirects failed: %s", err) | ||
return dir | ||
} | ||
if done { | ||
return dir | ||
} | ||
|
||
// Rewrites only happen if the target file does not exist | ||
if _, err = os.Stat(filepath.Join(dir, r.URL.Path)); err != nil { | ||
err = mf.processRewrites(r) | ||
if err != nil { | ||
log.Printf("Processing rewrites failed: %s", err) | ||
return dir | ||
} | ||
} | ||
|
||
err = mf.processHosting(w, r) | ||
if err != nil { | ||
log.Printf("Processing rewrites failed: %s", err) | ||
return dir | ||
} | ||
|
||
return dir | ||
} | ||
|
||
func readManifest(path string) (FirebaseManifest, error) { | ||
fmf := FirebaseManifest{} | ||
f, err := os.Open(path) | ||
if err != nil { | ||
return fmf, err | ||
} | ||
defer f.Close() | ||
dec := json.NewDecoder(f) | ||
err = dec.Decode(&fmf) | ||
return fmf, err | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.