Beispiel #1
0
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)
}
Beispiel #2
0
func wantsClosure(req *http.Request) bool {
	if req.Method == "GET" {
		suffix := httputil.PathSuffix(req)
		return closurePattern.MatchString(suffix)
	}
	return false
}
Beispiel #3
0
func getSuffixMatches(req *http.Request, pattern *regexp.Regexp) bool {
	if httputil.IsGet(req) {
		suffix := httputil.PathSuffix(req)
		return pattern.MatchString(suffix)
	}
	return false
}
Beispiel #4
0
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)
}
Beispiel #5
0
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)
}
Beispiel #6
0
func wantsClosure(req *http.Request) bool {
	if httputil.IsGet(req) {
		suffix := httputil.PathSuffix(req)
		return closurePattern.MatchString(suffix)
	}
	return false
}
Beispiel #7
0
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)
}
Beispiel #8
0
// 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)
}
Beispiel #9
0
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
}
Beispiel #10
0
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)
}
Beispiel #11
0
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)
}
Beispiel #12
0
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)
	}
}
Beispiel #13
0
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)
}
Beispiel #14
0
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)
	}
}
Beispiel #15
0
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)
}
Beispiel #16
0
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)
	}
}
Beispiel #17
0
// 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)
	}

}
Beispiel #18
0
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)
}
Beispiel #19
0
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)
	}
}
Beispiel #20
0
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)
	}
}
Beispiel #21
0
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)
	}
}
Beispiel #22
0
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)
}
Beispiel #23
0
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)
}
Beispiel #24
0
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
}
Beispiel #25
0
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)
}
Beispiel #26
0
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,
	}
}
Beispiel #27
0
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)
}
Beispiel #28
0
func wantsBlobRef(req *http.Request) bool {
	_, ok := blob.ParseKnown(httputil.PathSuffix(req))
	return ok
}
Beispiel #29
0
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)
}