package imgbundler import ( "bytes" "context" "encoding/base64" "fmt" "io/ioutil" "net/http" "net/url" "os" "regexp" "strings" "sync" "time" "golang.org/x/xerrors" "oss.terrastruct.com/xdefer" "oss.terrastruct.com/d2/lib/xmain" ) const maxImageSize int64 = 1 << 25 // 33_554_432 var imageRegex = regexp.MustCompile(` 0 { return svg, xerrors.Errorf("failed to bundle the following images: %v", errhrefs) } return svg, nil } svg = bytes.Replace(svg, repl.from, repl.to, 1) } } } // filterImageElements finds all image elements in imgs that are eligible // for bundling in the current context. func filterImageElements(imgs [][][]byte, isRemote bool) [][][]byte { imgs2 := imgs[:0] for _, img := range imgs { href := string(img[1]) // Skip already bundled images. if strings.HasPrefix(href, "data:") { continue } u, err := url.Parse(href) isRemoteImg := err == nil && strings.HasPrefix(u.Scheme, "http") if isRemoteImg == isRemote { imgs2 = append(imgs2, img) } } return imgs2 } var httpClient = &http.Client{} func httpGet(ctx context.Context, href string) ([]byte, error) { ctx, cancel := context.WithTimeout(ctx, time.Minute) defer cancel() req, err := http.NewRequestWithContext(ctx, "GET", href, nil) if err != nil { return nil, err } resp, err := httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, fmt.Errorf("expected status 200 but got %d %s", resp.StatusCode, resp.Status) } r := http.MaxBytesReader(nil, resp.Body, maxImageSize) return ioutil.ReadAll(r) }