func (sh *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { suffix := httputil.PathSuffix(req) handlers := getHandler switch { case httputil.IsGet(req): // use default from above case req.Method == "POST": handlers = postHandler default: handlers = nil } fn := handlers[strings.TrimPrefix(suffix, "camli/search/")] if fn != nil { fn(sh, rw, req) return } // TODO: discovery for the endpoints & better error message with link to discovery info ret := camtypes.SearchErrorResponse{ Error: "Unsupported search path or method", ErrorType: "input", } httputil.ReturnJSON(rw, &ret) }
func wantsClosure(req *http.Request) bool { if req.Method == "GET" { suffix := httputil.PathSuffix(req) return closurePattern.MatchString(suffix) } return false }
func getSuffixMatches(req *http.Request, pattern *regexp.Regexp) bool { if httputil.IsGet(req) { suffix := httputil.PathSuffix(req) return pattern.MatchString(suffix) } return false }
func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { base := httputil.PathBase(req) subPath := httputil.PathSuffix(req) switch req.Method { case "GET", "HEAD": switch subPath { case "": http.Redirect(rw, req, base+"camli/sig/discovery", http.StatusFound) return case h.pubKeyBlobRefServeSuffix: h.pubKeyHandler.ServeHTTP(rw, req) return case "camli/sig/sign": fallthrough case "camli/sig/verify": http.Error(rw, "POST required", 400) return case "camli/sig/discovery": httputil.ReturnJSON(rw, h.DiscoveryMap(base)) return } case "POST": switch subPath { case "camli/sig/sign": h.handleSign(rw, req) return case "camli/sig/verify": h.handleVerify(rw, req) return } } http.Error(rw, "Unsupported path or method.", http.StatusBadRequest) }
func (ui *UIHandler) serveDownload(rw http.ResponseWriter, req *http.Request) { if ui.root.Storage == nil { http.Error(rw, "No BlobRoot configured", 500) return } suffix := httputil.PathSuffix(req) m := downloadPattern.FindStringSubmatch(suffix) if m == nil { httputil.ErrorRouting(rw, req) return } fbr, ok := blob.Parse(m[1]) if !ok { http.Error(rw, "Invalid blobref", 400) return } dh := &DownloadHandler{ Fetcher: ui.root.Storage, Cache: ui.Cache, } dh.ServeHTTP(rw, req, fbr) }
func wantsClosure(req *http.Request) bool { if httputil.IsGet(req) { suffix := httputil.PathSuffix(req) return closurePattern.MatchString(suffix) } return false }
func (ui *UIHandler) serveFileTree(rw http.ResponseWriter, req *http.Request) { if ui.root.Storage == nil { http.Error(rw, "No BlobRoot configured", 500) return } suffix := httputil.PathSuffix(req) m := treePattern.FindStringSubmatch(suffix) if m == nil { httputil.ErrorRouting(rw, req) return } blobref, ok := blob.Parse(m[1]) if !ok { http.Error(rw, "Invalid blobref", 400) return } fth := &FileTreeHandler{ Fetcher: ui.root.Storage, file: blobref, } fth.ServeHTTP(rw, req) }
// ServeHTTP serves: // http://host/importer/ // http://host/importer/twitter/ // http://host/importer/twitter/callback // http://host/importer/twitter/sha1-abcabcabcabcabc (single account) func (h *Host) ServeHTTP(w http.ResponseWriter, r *http.Request) { suffix := httputil.PathSuffix(r) seg := strings.Split(suffix, "/") if suffix == "" || len(seg) == 0 { h.serveImportersRoot(w, r) return } impName := seg[0] imp, ok := h.imp[impName] if !ok { http.NotFound(w, r) return } if len(seg) == 1 || seg[1] == "" { h.serveImporter(w, r, imp) return } if seg[1] == "callback" { h.serveImporterAcctCallback(w, r, imp) return } acctRef, ok := blob.Parse(seg[1]) if !ok { http.NotFound(w, r) return } h.serveImporterAccount(w, r, imp, acctRef) }
func (h *shareHandler) serveHTTP(rw http.ResponseWriter, req *http.Request) error { var err error pathSuffix := httputil.PathSuffix(req) if len(pathSuffix) == 0 { // This happens during testing because we don't go through PrefixHandler pathSuffix = strings.TrimLeft(req.URL.Path, "/") } pathParts := strings.SplitN(pathSuffix, "/", 2) blobRef, ok := blob.Parse(pathParts[0]) if !ok { err = &shareError{code: invalidURL, response: badRequest, message: fmt.Sprintf("Malformed share pathSuffix: %s", pathSuffix)} } else { err = handleGetViaSharing(rw, req, blobRef, h.fetcher) } if se, ok := err.(*shareError); ok { switch se.response { case badRequest: httputil.BadRequestError(rw, err.Error()) case unauthorizedRequest: log.Print(err) auth.SendUnauthorized(rw, req) } } return err }
func (h *shareHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { blobRef, ok := blob.Parse(httputil.PathSuffix(req)) if !ok { http.Error(rw, "Malformed share URL.", 400) return } handleGetViaSharing(rw, req, blobRef, h.fetcher) }
func (h *shareHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { pathSuffix := httputil.PathSuffix(req) pathParts := strings.SplitN(pathSuffix, "/", 2) blobRef, ok := blob.Parse(pathParts[0]) if !ok { http.Error(rw, fmt.Sprintf("Malformed share pathSuffix: %s", pathSuffix), 400) return } handleGetViaSharing(rw, req, blobRef, h.fetcher) }
func (ui *UIHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { suffix := httputil.PathSuffix(req) rw.Header().Set("Vary", "Accept") switch { case wantsDiscovery(req): ui.root.serveDiscovery(rw, req) case wantsUploadHelper(req): ui.serveUploadHelper(rw, req) case strings.HasPrefix(suffix, "download/"): ui.serveDownload(rw, req) case strings.HasPrefix(suffix, "thumbnail/"): ui.serveThumbnail(rw, req) case strings.HasPrefix(suffix, "tree/"): ui.serveFileTree(rw, req) case strings.HasPrefix(suffix, "qr/"): ui.serveQR(rw, req) case getSuffixMatches(req, closurePattern): ui.serveClosure(rw, req) case getSuffixMatches(req, lessPattern): ui.serveFromDiskOrStatic(rw, req, lessPattern, ui.fileLessHandler, lessstatic.Files) case getSuffixMatches(req, reactPattern): ui.serveFromDiskOrStatic(rw, req, reactPattern, ui.fileReactHandler, reactstatic.Files) case getSuffixMatches(req, glitchPattern): ui.serveFromDiskOrStatic(rw, req, glitchPattern, ui.fileGlitchHandler, glitchstatic.Files) case getSuffixMatches(req, fontawesomePattern): ui.serveFromDiskOrStatic(rw, req, fontawesomePattern, ui.fileFontawesomeHandler, fontawesomestatic.Files) default: file := "" if m := staticFilePattern.FindStringSubmatch(suffix); m != nil { file = m[1] } else { switch { case wantsBlobRef(req): file = "index.html" case wantsPermanode(req): file = "permanode.html" case wantsBlobInfo(req): file = "blobinfo.html" case wantsFileTreePage(req): file = "filetree.html" case req.URL.Path == httputil.PathBase(req): file = "index.html" default: http.Error(rw, "Illegal URL.", http.StatusNotFound) return } } if file == "deps.js" { serveDepsJS(rw, req, ui.uiDir) return } ServeStaticFile(rw, req, uistatic.Files, file) } }
func (sh *StatusHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { suffix := httputil.PathSuffix(req) if req.Method != "GET" { http.Error(rw, "Illegal URL.", http.StatusMethodNotAllowed) return } if suffix == "status.json" { sh.serveStatus(rw, req) return } http.Error(rw, "Illegal URL.", 404) }
func (hh *HelpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { suffix := httputil.PathSuffix(req) if !httputil.IsGet(req) { http.Error(rw, "Illegal help method.", http.StatusMethodNotAllowed) return } switch suffix { case "": hh.serveHelpHTML(rw, req) default: http.Error(rw, "Illegal help path.", http.StatusNotFound) } }
func (a *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if camhttputil.PathSuffix(req) == "config.json" { if a.auth.AllowedAccess(req)&auth.OpGet == auth.OpGet { camhttputil.ReturnJSON(rw, a.appConfig) } else { auth.SendUnauthorized(rw, req) } return } if a.proxy == nil { http.Error(rw, "no proxy for the app", 500) return } a.proxy.ServeHTTP(rw, req) }
func (sh *StatusHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { suffix := httputil.PathSuffix(req) if !httputil.IsGet(req) { http.Error(rw, "Illegal status method.", http.StatusMethodNotAllowed) return } switch suffix { case "status.json": sh.serveStatusJSON(rw, req) case "": sh.serveStatusHTML(rw, req) default: http.Error(rw, "Illegal status path.", 404) } }
// serveFromDiskOrStatic matches rx against req's path and serves the match either from disk (if non-nil) or from static (embedded in the binary). func (ui *UIHandler) serveFromDiskOrStatic(rw http.ResponseWriter, req *http.Request, rx *regexp.Regexp, disk http.Handler, static *fileembed.Files) { suffix := httputil.PathSuffix(req) m := rx.FindStringSubmatch(suffix) if m == nil { panic("Caller should verify that rx matches") } file := m[1] if disk != nil { req.URL.Path = "/" + file disk.ServeHTTP(rw, req) } else { serveStaticFile(rw, req, static, file) } }
func (ui *UIHandler) serveClosure(rw http.ResponseWriter, req *http.Request) { suffix := httputil.PathSuffix(req) if ui.closureHandler == nil { log.Printf("%v not served: closure handler is nil", suffix) http.NotFound(rw, req) return } m := closurePattern.FindStringSubmatch(suffix) if m == nil { httputil.ErrorRouting(rw, req) return } req.URL.Path = "/" + m[1] ui.closureHandler.ServeHTTP(rw, req) }
func (ui *UIHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { suffix := httputil.PathSuffix(req) rw.Header().Set("Vary", "Accept") switch { case wantsDiscovery(req): ui.root.serveDiscovery(rw, req) case wantsUploadHelper(req): ui.serveUploadHelper(rw, req) case strings.HasPrefix(suffix, "download/"): ui.serveDownload(rw, req) case strings.HasPrefix(suffix, "thumbnail/"): ui.serveThumbnail(rw, req) case strings.HasPrefix(suffix, "tree/"): ui.serveFileTree(rw, req) case wantsClosure(req): ui.serveClosure(rw, req) default: file := "" if m := staticFilePattern.FindStringSubmatch(suffix); m != nil { file = m[1] } else { switch { case wantsPermanode(req): file = "permanode.html" case wantsBlobInfo(req): file = "blobinfo.html" case wantsFileTreePage(req): file = "filetree.html" case req.URL.Path == httputil.PathBase(req): file = "index.html" default: http.Error(rw, "Illegal URL.", http.StatusNotFound) return } } if file == "deps.js" { envVar := uiFiles.OverrideEnv if envVar != "" && os.Getenv(envVar) != "" { serveDepsJS(rw, req) return } } serveStaticFile(rw, req, uiFiles, file) } }
func (hh *HelpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { suffix := httputil.PathSuffix(req) if !httputil.IsGet(req) { http.Error(rw, "Illegal help method.", http.StatusMethodNotAllowed) return } switch suffix { case "": if clientConfig := req.FormValue("clientConfig"); clientConfig != "" { if clientConfigOnly, err := strconv.ParseBool(clientConfig); err == nil && clientConfigOnly { httputil.ReturnJSON(rw, hh.clientConfig) return } } hh.serveHelpHTML(rw, req) default: http.Error(rw, "Illegal help path.", http.StatusNotFound) } }
func (h *Host) ServeHTTP(w http.ResponseWriter, r *http.Request) { if httputil.PathSuffix(r) == "" { switch r.FormValue("mode") { case "": case "start": h.start() case "stop": h.stop() default: fmt.Fprintf(w, "Unknown mode") } h.mu.Lock() defer h.mu.Unlock() fmt.Fprintf(w, "I am an importer of type %T; running=%v; last progress=%#v", h.imp, h.running, h.lastProgress) } else { // TODO(aa): Remove this temporary hack once the UI has a way to configure importers. h.imp.ServeHTTP(w, r) } }
func (ui *UIHandler) serveThumbnail(rw http.ResponseWriter, req *http.Request) { if ui.root.Storage == nil { http.Error(rw, "No BlobRoot configured", 500) return } suffix := httputil.PathSuffix(req) m := thumbnailPattern.FindStringSubmatch(suffix) if m == nil { httputil.ErrorRouting(rw, req) return } query := req.URL.Query() width, _ := strconv.Atoi(query.Get("mw")) height, _ := strconv.Atoi(query.Get("mh")) blobref, ok := blob.Parse(m[1]) if !ok { http.Error(rw, "Invalid blobref", 400) return } if width == 0 { width = search.MaxImageSize } if height == 0 { height = search.MaxImageSize } th := &ImageHandler{ Fetcher: ui.root.Storage, Cache: ui.Cache, MaxWidth: width, MaxHeight: height, ThumbMeta: ui.thumbMeta, ResizeSem: ui.resizeSem, Search: ui.search, } th.ServeHTTP(rw, req, blobref) }
func (ui *UIHandler) serveThumbnail(rw http.ResponseWriter, req *http.Request) { if ui.root.Storage == nil { http.Error(rw, "No BlobRoot configured", 500) return } suffix := httputil.PathSuffix(req) m := thumbnailPattern.FindStringSubmatch(suffix) if m == nil { httputil.ErrorRouting(rw, req) return } query := req.URL.Query() width, err := strconv.Atoi(query.Get("mw")) if err != nil { http.Error(rw, "Invalid specified max width 'mw'", 500) return } height, err := strconv.Atoi(query.Get("mh")) if err != nil { http.Error(rw, "Invalid specified height 'mh'", 500) return } blobref := blobref.Parse(m[1]) if blobref == nil { http.Error(rw, "Invalid blobref", 400) return } th := &ImageHandler{ Fetcher: ui.root.Storage, Cache: ui.Cache, MaxWidth: width, MaxHeight: height, sc: ui.sc, } th.ServeHTTP(rw, req, blobref) }
func (ph *publishHandler) NewRequest(rw http.ResponseWriter, req *http.Request) (*publishRequest, error) { // splits a path request into its suffix and subresource parts. // e.g. /blog/foo/camli/res/file/xxx -> ("foo", "file/xxx") suffix, res := httputil.PathSuffix(req), "" if strings.HasPrefix(suffix, "-/") { suffix, res = "", suffix[2:] } else if s := strings.SplitN(suffix, "/-/", 2); len(s) == 2 { suffix, res = s[0], s[1] } return &publishRequest{ ph: ph, rw: rw, req: req, suffix: suffix, base: httputil.PathBase(req), subres: res, rootpn: ph.rootNode, inSubjectChain: make(map[string]bool), subjectBasePath: "", }, nil }
func (sh *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { ret := jsonMap() suffix := httputil.PathSuffix(req) if req.Method == "GET" { switch suffix { case "camli/search/recent": sh.serveRecentPermanodes(rw, req) return case "camli/search/permanodeattr": sh.servePermanodesWithAttr(rw, req) return case "camli/search/describe": sh.serveDescribe(rw, req) return case "camli/search/claims": sh.serveClaims(rw, req) return case "camli/search/files": sh.serveFiles(rw, req) return case "camli/search/signerattrvalue": sh.serveSignerAttrValue(rw, req) return case "camli/search/signerpaths": sh.serveSignerPaths(rw, req) return case "camli/search/edgesto": sh.serveEdgesTo(rw, req) return } } // TODO: discovery for the endpoints & better error message with link to discovery info ret["error"] = "Unsupported search path or method" ret["errorType"] = "input" httputil.ReturnJSON(rw, ret) }
func (ph *PublishHandler) NewRequest(rw http.ResponseWriter, req *http.Request) *publishRequest { // splits a path request into its suffix and subresource parts. // e.g. /blog/foo/camli/res/file/xxx -> ("foo", "file/xxx") suffix, res := httputil.PathSuffix(req), "" if strings.HasPrefix(suffix, "-/") { suffix, res = "", suffix[2:] } else if s := strings.SplitN(suffix, "/-/", 2); len(s) == 2 { suffix, res = s[0], s[1] } rootpn, _ := ph.rootPermanode() return &publishRequest{ ph: ph, rw: rw, req: req, suffix: suffix, base: httputil.PathBase(req), subres: res, rootpn: rootpn, dr: ph.Search.NewDescribeRequest(), inSubjectChain: make(map[string]bool), subjectBasePath: "", resizeSem: ph.resizeSem, } }
func (sh *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { ret := jsonMap() suffix := httputil.PathSuffix(req) if httputil.IsGet(req) { fn := getHandler[strings.TrimPrefix(suffix, "camli/search/")] if fn != nil { fn(sh, rw, req) return } } if req.Method == "POST" { switch suffix { case "camli/search/query": sh.serveQuery(rw, req) return } } // TODO: discovery for the endpoints & better error message with link to discovery info ret["error"] = "Unsupported search path or method" ret["errorType"] = "input" httputil.ReturnJSON(rw, ret) }
func wantsBlobRef(req *http.Request) bool { _, ok := blob.ParseKnown(httputil.PathSuffix(req)) return ok }
func (base closureRedirector) ServeHTTP(rw http.ResponseWriter, req *http.Request) { newURL := string(base) + "/" + path.Clean(httputil.PathSuffix(req)) http.Redirect(rw, req, newURL, http.StatusTemporaryRedirect) }