func (sh *Handler) serveSignerPaths(rw http.ResponseWriter, req *http.Request) { ret := jsonMap() defer httputil.ReturnJson(rw, ret) defer setPanicError(ret) signer := blobref.MustParse(mustGet(req, "signer")) target := blobref.MustParse(mustGet(req, "target")) paths, err := sh.index.PathsOfSignerTarget(signer, target) if err != nil { ret["error"] = err.String() } else { jpaths := []map[string]interface{}{} for _, path := range paths { jpaths = append(jpaths, map[string]interface{}{ "claimRef": path.Claim.String(), "baseRef": path.Base.String(), "suffix": path.Suffix, }) } ret["paths"] = jpaths dr := sh.NewDescribeRequest() for _, path := range paths { dr.Describe(path.Base, 2) } dr.PopulateJSON(ret) } }
func (fi *FakeIndex) AddClaim(owner, permanode *blobref.BlobRef, claimType, attr, value string) { fi.lk.Lock() defer fi.lk.Unlock() date := fi.nextDate() claim := &search.Claim{ Permanode: permanode, Signer: nil, BlobRef: nil, Date: date, Type: claimType, Attr: attr, Value: value, } key := permanode.String() + "/" + owner.String() fi.ownerClaims[key] = append(fi.ownerClaims[key], claim) if claimType == "set-attribute" && strings.HasPrefix(attr, "camliPath:") { suffix := attr[len("camliPath:"):] path := &search.Path{ Target: blobref.MustParse(value), Suffix: suffix, } fi.path[fmt.Sprintf("%s\x00%s\x00%s", owner, permanode, suffix)] = path } }
func (mi *Indexer) PathsOfSignerTarget(signer, target *blobref.BlobRef) (paths []*search.Path, err os.Error) { keyId, err := mi.keyIdOfSigner(signer) if err != nil { return } rs, err := mi.db.Query("SELECT claimref, claimdate, baseref, suffix, active FROM path WHERE keyid=? AND targetref=?", keyId, target.String()) if err != nil { return } defer rs.Close() mostRecent := make(map[string]*search.Path) maxClaimDates := make(map[string]string) var claimRef, claimDate, baseRef, suffix, active string for rs.Next() { if err = rs.Scan(&claimRef, &claimDate, &baseRef, &suffix, &active); err != nil { return } key := baseRef + "/" + suffix if claimDate > maxClaimDates[key] { maxClaimDates[key] = claimDate if active == "Y" { mostRecent[key] = &search.Path{ Claim: blobref.MustParse(claimRef), ClaimDate: claimDate, Base: blobref.MustParse(baseRef), Suffix: suffix, } } else { mostRecent[key] = nil, false } } } paths = make([]*search.Path, 0) for _, v := range mostRecent { paths = append(paths, v) } return paths, nil }
func TestDescribe(t *testing.T) { for testn, tt := range describeTests { idx := test.NewFakeIndex() tt.setup(idx) h := NewHandler(idx, owner) js := make(map[string]interface{}) dr := h.NewDescribeRequest() dr.Describe(blobref.MustParse(tt.blob), tt.depth) dr.PopulateJSON(js) got, _ := json.MarshalIndent(js, "", " ") want, _ := json.MarshalIndent(tt.expect, "", " ") if !bytes.Equal(got, want) { t.Errorf("test %d:\nwant: %s\n got: %s", testn, string(want), string(got)) } } }
func (sh *Handler) serveSignerAttrValue(rw http.ResponseWriter, req *http.Request) { ret := jsonMap() defer httputil.ReturnJson(rw, ret) defer setPanicError(ret) signer := blobref.MustParse(mustGet(req, "signer")) attr := mustGet(req, "attr") value := mustGet(req, "value") pn, err := sh.index.PermanodeOfSignerAttrValue(signer, attr, value) if err != nil { ret["error"] = err.String() } else { ret["permanode"] = pn.String() dr := sh.NewDescribeRequest() dr.Describe(pn, 2) dr.PopulateJSON(ret) } }
func TestPublishURLs(t *testing.T) { owner := blobref.MustParse("owner-123") picNode := blobref.MustParse("picpn-123") galRef := blobref.MustParse("gal-123") rootRef := blobref.MustParse("root-abc") camp0 := blobref.MustParse("picpn-98765432100") camp1 := blobref.MustParse("picpn-98765432111") camp0f := blobref.MustParse("picfile-f00f00f00a5") camp1f := blobref.MustParse("picfile-f00f00f00b6") rootName := "foo" for ti, tt := range publishURLTests { idx := test.NewFakeIndex() idx.AddSignerAttrValue(owner, "camliRoot", rootName, rootRef) sh := search.NewHandler(idx, owner) ph := &PublishHandler{ RootName: rootName, Search: sh, } idx.AddMeta(owner, "text/x-openpgp-public-key", 100) for _, br := range []*blobref.BlobRef{picNode, galRef, rootRef, camp0, camp1} { idx.AddMeta(br, "application/json; camliType=permanode", 100) } for _, br := range []*blobref.BlobRef{camp0f, camp1f} { idx.AddMeta(br, "application/json; camliType=file", 100) } idx.AddClaim(owner, rootRef, "set-attribute", "camliPath:singlepic", picNode.String()) idx.AddClaim(owner, rootRef, "set-attribute", "camliPath:camping", galRef.String()) idx.AddClaim(owner, galRef, "add-attribute", "camliMember", camp0.String()) idx.AddClaim(owner, galRef, "add-attribute", "camliMember", camp1.String()) idx.AddClaim(owner, camp0, "set-attribute", "camliContent", camp0f.String()) idx.AddClaim(owner, camp1, "set-attribute", "camliContent", camp1f.String()) rw := httptest.NewRecorder() if !strings.HasPrefix(tt.path, "/pics/") { panic("expected /pics/ prefix on " + tt.path) } req, _ := http.NewRequest("GET", "http://foo.com"+tt.path, nil) pfxh := &httputil.PrefixHandler{ Prefix: "/pics/", Handler: http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) { pr := ph.NewRequest(rw, req) err := pr.findSubject() if tt.subject != "" { if err != nil { t.Errorf("test #%d, findSubject: %v", ti, err) return } if pr.subject.String() != tt.subject { t.Errorf("test #%d, got subject %q, want %q", ti, pr.subject, tt.subject) } } if pr.subres != tt.subres { t.Errorf("test #%d, got subres %q, want %q", ti, pr.subres, tt.subres) } }), } pfxh.ServeHTTP(rw, req) } }
"testing" "camli/blobref" "camli/test" ) type describeTest struct { setup func(fi *test.FakeIndex) blob string // blobref to describe depth int expect map[string]interface{} } var owner = blobref.MustParse("abcown-123") var describeTests = []describeTest{ { func(fi *test.FakeIndex) {}, "abc-555", 1, map[string]interface{}{}, }, { func(fi *test.FakeIndex) { fi.AddMeta(blobref.MustParse("abc-555"), "image/jpeg", 999) }, "abc-555", 1,
// TODO(mpl): configure and/or document the name of the possible attributes in the http request func (sh *Handler) servePermanodesWithAttr(rw http.ResponseWriter, req *http.Request) { ret := jsonMap() defer httputil.ReturnJson(rw, ret) defer setPanicError(ret) signer := blobref.MustParse(mustGet(req, "signer")) value := mustGet(req, "value") fuzzy := req.FormValue("fuzzy") // exact match if empty fuzzyMatch := false if fuzzy != "" { lowered := strings.ToLower(fuzzy) if lowered == "true" || lowered == "t" { fuzzyMatch = true } } attr := req.FormValue("attr") // all attributes if empty if attr == "" { // and force fuzzy in that case. fuzzyMatch = true } maxResults := maxPermanodes max := req.FormValue("max") if max != "" { maxR, err := strconv.Atoi(max) if err != nil { log.Printf("Invalid specified max results 'max': " + err.String()) return } if maxR < maxResults { maxResults = maxR } } ch := make(chan *blobref.BlobRef, buffered) errch := make(chan os.Error) go func() { errch <- sh.index.SearchPermanodesWithAttr(ch, &PermanodeByAttrRequest{Attribute: attr, Query: value, Signer: signer, FuzzyMatch: fuzzyMatch, MaxResults: maxResults}) }() dr := sh.NewDescribeRequest() withAttr := jsonMapList() for res := range ch { dr.Describe(res, 2) jm := jsonMap() jm["permanode"] = res.String() withAttr = append(withAttr, jm) } err := <-errch if err != nil { ret["error"] = err.String() ret["errorType"] = "server" return } ret["withAttr"] = withAttr dr.PopulateJSON(ret) }