예제 #1
0
// handleMasterQuery allows an app to register the master query that defines the
// domain limiting all subsequent search queries.
func (a *Handler) handleMasterQuery(w http.ResponseWriter, r *http.Request) {
	if !(a.auth.AllowedAccess(r)&auth.OpAll == auth.OpAll) {
		auth.SendUnauthorized(w, r)
		return
	}
	if r.Method != http.MethodPost {
		http.Error(w, "not a POST", http.StatusMethodNotAllowed)
		return
	}
	if a.sh == nil {
		http.Error(w, "app proxy has no search handler", 500)
		return
	}
	if refresh, _ := strconv.ParseBool(r.FormValue("refresh")); refresh {
		if err := a.refreshDomainBlobs(); err != nil {
			if err == errRefreshSuppress {
				http.Error(w, "too many refresh requests", http.StatusTooManyRequests)
			} else {
				http.Error(w, fmt.Sprintf("%v", err), 500)
			}
			return
		}
		w.Write([]byte("OK"))
		return
	}
	sq := new(search.SearchQuery)
	if err := sq.FromHTTP(r); err != nil {
		http.Error(w, fmt.Sprintf("error reading master query: %v", err), 500)
		return
	}
	var masterQuery search.SearchQuery = *(sq)
	des := *(masterQuery.Describe)
	masterQuery.Describe = &des
	sr, err := a.sh.Query(sq)
	if err != nil {
		http.Error(w, fmt.Sprintf("error running master query: %v", err), 500)
		return
	}
	a.masterQueryMu.Lock()
	defer a.masterQueryMu.Unlock()
	a.masterQuery = &masterQuery
	a.domainBlobs = make(map[blob.Ref]bool, len(sr.Describe.Meta))
	for _, v := range sr.Describe.Meta {
		a.domainBlobs[v.BlobRef] = true
	}
	a.domainBlobsRefresh = time.Now()
	w.Write([]byte("OK"))
}
예제 #2
0
// handleSearch runs the requested search query against the search handler, and
// if the results are within the domain allowed by the master query, forwards them
// back to the client.
func (a *Handler) handleSearch(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		camhttputil.BadRequestError(w, camhttputil.InvalidMethodError{}.Error())
		return
	}
	if a.sh == nil {
		http.Error(w, "app proxy has no search handler", 500)
		return
	}
	a.masterQueryMu.RLock()
	if a.masterQuery == nil {
		http.Error(w, "search is not allowed", http.StatusForbidden)
		a.masterQueryMu.RUnlock()
		return
	}
	a.masterQueryMu.RUnlock()
	var sq search.SearchQuery
	if err := sq.FromHTTP(r); err != nil {
		camhttputil.ServeJSONError(w, err)
		return
	}
	sr, err := a.sh.Query(&sq)
	if err != nil {
		camhttputil.ServeJSONError(w, err)
		return
	}
	// check this search is in the allowed domain
	if !a.allowProxySearchResponse(sr) {
		// there's a chance our domainBlobs cache is expired so let's
		// refresh it and retry, but no more than once per minute.
		if err := a.refreshDomainBlobs(); err != nil {
			http.Error(w, "search scope is forbidden", http.StatusForbidden)
			return
		}
		if !a.allowProxySearchResponse(sr) {
			http.Error(w, "search scope is forbidden", http.StatusForbidden)
			return
		}
	}
	camhttputil.ReturnJSON(w, sr)
}
예제 #3
0
func (c *Client) Query(req *search.SearchQuery) (*search.SearchResult, error) {
	sr, err := c.SearchRoot()
	if err != nil {
		return nil, err
	}
	url := sr + req.URLSuffix()
	body, err := json.MarshalIndent(req, "", "\t")
	if err != nil {
		return nil, err
	}
	hreq := c.newRequest("POST", url, bytes.NewReader(body))
	hres, err := c.expect2XX(hreq)
	if err != nil {
		return nil, err
	}
	res := new(search.SearchResult)
	if err := httputil.DecodeJSON(hres, res); err != nil {
		return nil, err
	}
	return res, nil
}
예제 #4
0
func (c *Client) Search(req *search.SearchQuery) (*search.SearchResult, error) {
	sr, err := c.SearchRoot()
	if err != nil {
		return nil, err
	}
	url := sr + req.URLSuffix()
	body, err := json.MarshalIndent(req, "", "\t")
	if err != nil {
		return nil, err
	}
	hreq := c.newRequest("POST", url, bytes.NewReader(body))
	hres, err := c.doReqGated(hreq)
	if err != nil {
		return nil, err
	}
	defer hres.Body.Close()
	res := new(search.SearchResult)
	if err := json.NewDecoder(hres.Body).Decode(res); err != nil {
		return nil, err
	}
	return res, nil
}
예제 #5
0
func (a *Handler) refreshDomainBlobs() error {
	a.masterQueryMu.Lock()
	defer a.masterQueryMu.Unlock()
	if time.Now().Before(a.domainBlobsRefresh.Add(time.Minute)) {
		// suppress refresh request to no more than once per minute
		return errRefreshSuppress
	}
	if a.masterQuery == nil {
		return errors.New("no master query")
	}
	var sq search.SearchQuery = *(a.masterQuery)
	des := *(sq.Describe)
	sq.Describe = &des
	sr, err := a.sh.Query(&sq)
	if err != nil {
		return fmt.Errorf("error running master query: %v", err)
	}
	a.domainBlobs = make(map[blob.Ref]bool, len(sr.Describe.Meta))
	for _, v := range sr.Describe.Meta {
		a.domainBlobs[v.BlobRef] = true
	}
	a.domainBlobsRefresh = time.Now()
	return nil
}