func (this *Source) fromUrl(s string) *Source { if s == "" { return nil } var err error parts := strings.Split(s, "://") switch len(parts) { case NOPROTO: this.scheme = config.Get().Scheme() this.filepath = filepath.Clean(parts[0]) break case URIFULL: this.scheme = parts[0] if strings.Contains(parts[1], "\x00") || strings.Contains(parts[1], "../") { log.Printf("URI containts illegal characters. `%v`\n", parts[1]) return nil } this.filepath = filepath.Clean(parts[1]) break default: log.Printf("Wrong URL = '%v'\n", s) return nil } this.root, err = config.Get().Root(this.scheme) if err != nil { log.Println("Unable to proceed without default root for `file` scheme.", err) return nil } if r, found := readers[this.scheme]; found { this.reader = r } if this.Blob() == nil { return nil } this.Imgcfg, this.imgtype, err = image.DecodeConfig(bytes.NewReader(this.Blob())) if err != nil { log.Printf("Unable to DecodeConfig() for resource from %v. %v\n", this.Link(), err) return nil } return this }
func main() { dumpcfg := flag.Bool("dumpcfg", false, "Dump config.") flag.Usage = func() { fmt.Fprintf(os.Stdout, "Usage: %s [OPTIONS]\n", os.Args[0]) flag.PrintDefaults() } flag.Parse() if *dumpcfg { config.Get().DumpCfg() os.Exit(0) } initCacheGroup() log.Printf("Service listen on %v\n", config.Get().Listen()) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { var data []byte var ctx groupcache.Context cacheGroup.Get(ctx, r.URL.String(), groupcache.AllocatingByteSliceSink(&data)) http.ServeContent(w, r, r.URL.String(), time.Now(), bytes.NewReader(data)) }, ) http.HandleFunc("/nocache", func(w http.ResponseWriter, r *http.Request) { var result []byte result = imgproc.Do(Construct(new(query.Options), r.URL).(*query.Options)) w.Write(result) }, ) http.HandleFunc("/stat", func(w http.ResponseWriter, r *http.Request) { // awesome stat. not implemented yet. }, ) log.Fatal(http.ListenAndServe(config.Get().Listen(), nil)) }
func initCacheGroup() { self := config.Get().CacheSelf() pool := groupcache.NewHTTPPool(self) pool.Set(config.Get().CachePeers()...) if self != "" { log.Println("Cache listen on:", strings.TrimLeft(self, "http://")) go http.ListenAndServe(strings.TrimLeft(self, "http://"), http.HandlerFunc(pool.ServeHTTP)) } cacheGroup = groupcache.NewGroup("imagio-storage", config.Get().CacheSize(), groupcache.GetterFunc( func(ctx groupcache.Context, key string, dest groupcache.Sink) error { dest.SetBytes(imgproc.Do( Construct(new(query.Options), key).(*query.Options), )) return nil }), ) }
func TestSource(t *testing.T) { var once sync.Once cases := map[string]*expected{ "http://" + test_server + "/" + file_name: &expected{&PixelDim{1024, 768}, "jpeg", "image/jpeg", false, test_server + "/" + file_name}, "": &expected{Size: nil, UseConfig: false}, "file://": &expected{Size: nil, UseConfig: false}, //file without 'root' option defined "localhost://../etc/passwd": &expected{Size: nil, UseConfig: false}, //wrong characters "file:// ": &expected{Size: nil, UseConfig: true}, "file://1024x768.jpg": &expected{&PixelDim{1024, 768}, "jpeg", "image/jpeg", true, "/tmp/1024x768.jpg"}, } for option, want := range cases { if want != nil && want.UseConfig { once.Do(func() { cfg := config.Get() cfg.Sources.File.Default = false cfg.Sources.File.Root = "/tmp" }) } src := Construct(new(Source), option).(*Source) if want.Size == nil && src != nil { t.Errorf("Expected nil, got %v\n", src) continue } if src != nil { if !reflect.DeepEqual(src.Size(), want.Size) { t.Errorf("Expected size is %v, got %v\n", want.Size, src.Size()) } if src.Type() != want.ImgType { t.Errorf("Expected image type is %v, got %v\n", want.ImgType, src.Type()) } if src.Mime() != want.MimeType { t.Errorf("Expected mime type is %v, got %v", src.Mime(), want.MimeType) } if src.Link() != want.Link { t.Errorf("Expected link is %v, got %v\n", want.Link, src.Link()) } } } }
func parseQuery(u *url.URL) *Options { query := u.Query() log.Println("in:", u.String()) this := &Options{ CropRoi: Construct(new(Roi), query.Get("crop")).(*Roi), Scale: Construct(new(Scale), query.Get("scale")).(*Scale), Base: Construct(new(Source), query.Get("source")).(*Source), Format: get(query.Get("format"), config.Get().Format()).(string), Method: get(query.Get("method"), config.Get().Method()).(int), Alpha: getFloat(query.Get("blend_alpha"), config.Get().Alpha()), Quality: getInt(query.Get("quality"), config.Get().Quality()), Foreground: Construct(new(Source), config.Get().BlendWith(query.Get("blend_with"))).(*Source), Mask: Construct(new(Source), config.Get().BlendMask(query.Get("blend_mask"))).(*Source), BlendRoi: Construct(new(Roi), config.Get().BlendRoi(query.Get("blend_roi"))).(*Roi), } return this }