Example #1
0
func realInit(w http.ResponseWriter, r *http.Request) bool {
	ctx := appengine.NewContext(r)

	errf := func(format string, args ...interface{}) bool {
		ctx.Errorf("In init: "+format, args...)
		http.Error(w, fmt.Sprintf(format, args...), 500)
		return false
	}

	config, err := serverinit.Load("./config.json")
	if err != nil {
		return errf("Could not load server config: %v", err)
	}

	// Update the config to use the URL path derived from the first App Engine request.
	// TODO(bslatkin): Support hostnames that aren't x.appspot.com
	scheme := "http"
	if r.TLS != nil {
		scheme = "https"
	}

	baseURL := fmt.Sprintf("%s://%s/", scheme, appengine.DefaultVersionHostname(ctx))
	ctx.Infof("baseurl = %q", baseURL)

	root.mux = http.NewServeMux()
	_, err = config.InstallHandlers(root.mux, baseURL, false, r)
	if err != nil {
		return errf("Error installing handlers: %v", err)
	}

	return true
}
Example #2
0
func TestExpansionsInHighlevelConfig(t *testing.T) {
	camroot, err := osutil.GoPackagePath("camlistore.org")
	if err != nil {
		t.Fatalf("failed to find camlistore.org GOPATH root: %v", err)
	}
	const keyID = "26F5ABDA"
	os.Setenv("TMP_EXPANSION_TEST", keyID)
	os.Setenv("TMP_EXPANSION_SECRING", filepath.Join(camroot, filepath.FromSlash("pkg/jsonsign/testdata/test-secring.gpg")))
	// Setting CAMLI_CONFIG_DIR to avoid triggering failInTests in osutil.CamliConfigDir
	defer os.Setenv("CAMLI_CONFIG_DIR", os.Getenv("CAMLI_CONFIG_DIR")) // restore after test
	os.Setenv("CAMLI_CONFIG_DIR", "whatever")
	conf, err := serverinit.Load([]byte(`
{
    "auth": "localhost",
    "listen": ":4430",
    "https": false,
    "identity": ["_env", "${TMP_EXPANSION_TEST}"],
    "identitySecretRing": ["_env", "${TMP_EXPANSION_SECRING}"],
    "googlecloudstorage": ":camlistore-dev-blobs",
    "kvIndexFile": "/tmp/camli-index.kvdb"
}
`))
	if err != nil {
		t.Fatal(err)
	}
	got := fmt.Sprintf("%#v", conf)
	if !strings.Contains(got, keyID) {
		t.Errorf("Expected key %s in resulting low-level config. Got: %s", keyID, got)
	}
}
Example #3
0
func (c *reindexdpCmd) RunCommand(args []string) error {
	var path string
	switch {
	case len(args) == 0:
		cfg, err := serverinit.Load(osutil.UserServerConfigPath())
		if err != nil {
			return err
		}
		prefixes, ok := cfg.Obj["prefixes"].(map[string]interface{})
		if !ok {
			return fmt.Errorf("No 'prefixes' object in low-level (or converted) config file %s", osutil.UserServerConfigPath())
		}
		paths := []string{}
		for prefix, vei := range prefixes {
			pmap, ok := vei.(map[string]interface{})
			if !ok {
				log.Printf("prefix %q value is a %T, not an object", prefix, vei)
				continue
			}
			pconf := jsonconfig.Obj(pmap)
			handlerType := pconf.RequiredString("handler")
			handlerArgs := pconf.OptionalObject("handlerArgs")
			// no pconf.Validate, as this is a recover tool
			if handlerType != "storage-diskpacked" {
				continue
			}
			if handlerArgs == nil {
				log.Printf("no handlerArgs for %q", prefix)
				continue
			}
			aconf := jsonconfig.Obj(handlerArgs)
			path = aconf.RequiredString("path")
			// no aconv.Validate, as this is a recover tool
			if path != "" {
				paths = append(paths, path)
			}
		}
		if len(paths) == 0 {
			return fmt.Errorf("Server config file %s doesn't specify a disk-packed storage handler.",
				osutil.UserServerConfigPath())
		}
		if len(paths) > 1 {
			return fmt.Errorf("Ambiguity. Server config file %s d specify more than 1 disk-packed storage handler. Please specify one of: %v", osutil.UserServerConfigPath(), paths)
		}
		path = paths[0]
	case len(args) == 1:
		path = args[0]
	default:
		return errors.New("More than 1 argument not allowed")
	}
	if path == "" {
		return errors.New("no path is given/found")
	}

	return diskpacked.Reindex(path, c.overwrite)
}
Example #4
0
// newTestServer creates a new test server with in memory storage for use in upload tests
func newTestServer(t *testing.T) *httptest.Server {
	camroot, err := osutil.GoPackagePath("camlistore.org")
	if err != nil {
		t.Fatalf("failed to find camlistore.org GOPATH root: %v", err)
	}

	conf := serverconfig.Config{
		Listen:             ":3179",
		HTTPS:              false,
		Auth:               "localhost",
		Identity:           "26F5ABDA",
		IdentitySecretRing: filepath.Join(camroot, filepath.FromSlash("pkg/jsonsign/testdata/test-secring.gpg")),
		MemoryStorage:      true,
		MemoryIndex:        true,
	}

	confData, err := json.MarshalIndent(conf, "", "    ")
	if err != nil {
		t.Fatalf("Could not json encode config: %v", err)
	}

	// Setting CAMLI_CONFIG_DIR to avoid triggering failInTests in osutil.CamliConfigDir
	defer os.Setenv("CAMLI_CONFIG_DIR", os.Getenv("CAMLI_CONFIG_DIR")) // restore after test
	os.Setenv("CAMLI_CONFIG_DIR", "whatever")
	lowConf, err := serverinit.Load(confData)
	if err != nil {
		t.Fatal(err)
	}
	// because these two are normally consumed in camlistored.go
	// TODO(mpl): serverinit.Load should consume these 2 as well. Once
	// consumed, we should keep all the answers as private fields, and then we
	// put accessors on serverinit.Config. Maybe we even stop embedding
	// jsonconfig.Obj in serverinit.Config too, so none of those methods are
	// accessible.
	lowConf.OptionalBool("https", true)
	lowConf.OptionalString("listen", "")

	reindex := false
	var context *http.Request // only used by App Engine. See handlerLoader in serverinit.go
	hi := http.NewServeMux()
	address := "http://" + conf.Listen
	_, err = lowConf.InstallHandlers(hi, address, reindex, context)
	if err != nil {
		t.Fatal(err)
	}

	return httptest.NewServer(hi)
}
Example #5
0
// loadConfig returns the server's parsed config file, locating it using the provided arg.
//
// The arg may be of the form:
// - empty, to mean automatic (will write a default high-level config if
//   no cloud config is available)
// - a filepath absolute or relative to the user's configuration directory,
// - a URL
func loadConfig(arg string) (conf *serverinit.Config, isNewConfig bool, err error) {
	if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") {
		contents, err := slurpURL(arg, 256<<10)
		if err != nil {
			return nil, false, err
		}
		conf, err = serverinit.Load(contents)
		return conf, false, err
	}
	var absPath string
	switch {
	case arg == "":
		absPath = osutil.UserServerConfigPath()
		_, err = wkfs.Stat(absPath)
		if err != nil {
			if !os.IsNotExist(err) {
				return
			}
			conf, err = serverinit.DefaultEnvConfig()
			if err != nil || conf != nil {
				return
			}
			err = wkfs.MkdirAll(osutil.CamliConfigDir(), 0700)
			if err != nil {
				return
			}
			log.Printf("Generating template config file %s", absPath)
			if err = serverinit.WriteDefaultConfigFile(absPath, sqlite.CompiledIn()); err == nil {
				isNewConfig = true
			}
		}
	case filepath.IsAbs(arg):
		absPath = arg
	default:
		absPath = filepath.Join(osutil.CamliConfigDir(), arg)
	}
	conf, err = serverinit.LoadFile(absPath)
	return
}
Example #6
0
func (c *dumpconfigCmd) RunCommand(args []string) error {
	var file string
	switch {
	case len(args) == 0:
		file = osutil.UserServerConfigPath()
	case len(args) == 1:
		file = args[0]
	default:
		return errors.New("More than 1 argument not allowed")
	}
	cfg, err := serverinit.Load(file)
	if err != nil {
		return err
	}
	cfg.Obj["handlerConfig"] = true
	ll, err := json.MarshalIndent(cfg.Obj, "", "  ")
	if err != nil {
		return err
	}
	_, err = os.Stdout.Write(ll)
	return err
}
Example #7
0
func TestInstallHandlers(t *testing.T) {
	camroot, err := osutil.GoPackagePath("camlistore.org")
	if err != nil {
		t.Fatalf("failed to find camlistore.org GOPATH root: %v", err)
	}
	conf := serverinit.DefaultBaseConfig
	conf.Identity = "26F5ABDA"
	conf.IdentitySecretRing = filepath.Join(camroot, filepath.FromSlash("pkg/jsonsign/testdata/test-secring.gpg"))
	conf.MemoryStorage = true
	conf.MemoryIndex = true

	confData, err := json.MarshalIndent(conf, "", "    ")
	if err != nil {
		t.Fatalf("Could not json encode config: %v", err)
	}

	// Setting CAMLI_CONFIG_DIR to avoid triggering failInTests in osutil.CamliConfigDir
	defer os.Setenv("CAMLI_CONFIG_DIR", os.Getenv("CAMLI_CONFIG_DIR")) // restore after test
	os.Setenv("CAMLI_CONFIG_DIR", "whatever")
	lowConf, err := serverinit.Load(confData)
	if err != nil {
		t.Fatal(err)
	}
	// because these two are normally consumed in camlistored.go
	// TODO(mpl): serverinit.Load should consume these 2 as well. Once
	// consumed, we should keep all the answers as private fields, and then we
	// put accessors on serverinit.Config. Maybe we even stop embedding
	// jsonconfig.Obj in serverinit.Config too, so none of those methods are
	// accessible.
	lowConf.OptionalBool("https", true)
	lowConf.OptionalString("listen", "")

	reindex := false
	var context *http.Request // only used by App Engine. See handlerLoader in serverinit.go
	hi := http.NewServeMux()
	address := "http://" + conf.Listen
	_, err = lowConf.InstallHandlers(hi, address, reindex, context)
	if err != nil {
		t.Fatal(err)
	}

	tests := []struct {
		prefix        string
		authWrapped   bool
		prefixWrapped bool
		handlerType   reflect.Type
	}{
		{
			prefix:        "/",
			handlerType:   reflect.TypeOf(&server.RootHandler{}),
			prefixWrapped: true,
		},

		{
			prefix:        "/sync/",
			handlerType:   reflect.TypeOf(&server.SyncHandler{}),
			prefixWrapped: true,
			authWrapped:   true,
		},

		{
			prefix:        "/my-search/",
			handlerType:   reflect.TypeOf(&search.Handler{}),
			prefixWrapped: true,
			authWrapped:   true,
		},

		{
			prefix:        "/ui/",
			handlerType:   reflect.TypeOf(&server.UIHandler{}),
			prefixWrapped: true,
			authWrapped:   true,
		},

		{
			prefix:        "/importer/",
			handlerType:   reflect.TypeOf(&importer.Host{}),
			prefixWrapped: true,
			authWrapped:   true,
		},

		{
			prefix:        "/sighelper/",
			handlerType:   reflect.TypeOf(&signhandler.Handler{}),
			prefixWrapped: true,
			authWrapped:   true,
		},

		{
			prefix:        "/status/",
			handlerType:   reflect.TypeOf(&server.StatusHandler{}),
			prefixWrapped: true,
			authWrapped:   true,
		},

		{
			prefix:        "/help/",
			handlerType:   reflect.TypeOf(&server.HelpHandler{}),
			prefixWrapped: true,
			authWrapped:   true,
		},

		{
			prefix:        "/setup/",
			handlerType:   reflect.TypeOf(&server.SetupHandler{}),
			prefixWrapped: true,
		},

		{
			prefix:      "/bs/camli/",
			handlerType: reflect.TypeOf(http.HandlerFunc(nil)),
		},

		{
			prefix:      "/index/camli/",
			handlerType: reflect.TypeOf(http.HandlerFunc(nil)),
		},

		{
			prefix:      "/bs-and-index/camli/",
			handlerType: reflect.TypeOf(http.HandlerFunc(nil)),
		},

		{
			prefix:      "/bs-and-maybe-also-index/camli/",
			handlerType: reflect.TypeOf(http.HandlerFunc(nil)),
		},

		{
			prefix:      "/cache/camli/",
			handlerType: reflect.TypeOf(http.HandlerFunc(nil)),
		},
	}
	for _, v := range tests {
		req, err := http.NewRequest("GET", address+v.prefix, nil)
		if err != nil {
			t.Error(err)
			continue
		}
		h, _ := hi.Handler(req)
		if v.authWrapped {
			ah, ok := h.(auth.Handler)
			if !ok {
				t.Errorf("handler for %v should be auth wrapped", v.prefix)
				continue
			}
			h = ah.Handler
		}
		if v.prefixWrapped {
			ph, ok := h.(*httputil.PrefixHandler)
			if !ok {
				t.Errorf("handler for %v should be prefix wrapped", v.prefix)
				continue
			}
			h = ph.Handler
		}
		if reflect.TypeOf(h) != v.handlerType {
			t.Errorf("for %v: want %v, got %v", v.prefix, v.handlerType, reflect.TypeOf(h))
		}
	}
}
Example #8
0
// Main sends on up when it's running, and shuts down when it receives from down.
func Main(up chan<- struct{}, down <-chan struct{}) {
	flag.Parse()

	if *flagVersion {
		fmt.Fprintf(os.Stderr, "camlistored version: %s\nGo version: %s (%s/%s)\n",
			buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH)
		return
	}
	if *flagReindex {
		index.SetImpendingReindex()
	}

	log.Printf("Starting camlistored version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(),
		runtime.GOOS, runtime.GOARCH)

	shutdownc := make(chan io.Closer, 1) // receives io.Closer to cleanly shut down
	go handleSignals(shutdownc)

	fileName, isNewConfig, err := findConfigFile(*flagConfigFile)
	if err != nil {
		exitf("Error finding config file %q: %v", fileName, err)
	}
	log.Printf("Using config file %s", fileName)
	config, err := serverinit.Load(fileName)
	if err != nil {
		exitf("Could not load server config: %v", err)
	}

	ws := webserver.New()
	listen, baseURL := listenAndBaseURL(config)

	setupTLS(ws, config, listen)

	err = ws.Listen(listen)
	if err != nil {
		exitf("Listen: %v", err)
	}

	if baseURL == "" {
		baseURL = ws.ListenURL()
	}

	shutdownCloser, err := config.InstallHandlers(ws, baseURL, *flagReindex, nil)
	if err != nil {
		exitf("Error parsing config: %v", err)
	}
	shutdownc <- shutdownCloser

	urlToOpen := baseURL
	if !isNewConfig {
		// user may like to configure the server at the initial startup,
		// open UI if this is not the first run with a new config file.
		urlToOpen += config.UIPath
	}

	log.Printf("Available on %s", urlToOpen)
	if *flagOpenBrowser {
		go osutil.OpenURL(urlToOpen)
	}

	go ws.Serve()
	if flagPollParent {
		osutil.DieOnParentDeath()
	}

	// Block forever, except during tests.
	up <- struct{}{}
	<-down
	osExit(0)
}