func (resp *APIResponse) UnmarshalJSON(data []byte) error {
	var m map[string]string
	if err := json.Unmarshal(data, &m); err != nil {
		return err
	}
	var expires time.Time
	expiresString := m[APIResponseKeyExpires]
	if err := expires.UnmarshalJSON([]byte(`"` + expiresString + `"`)); err != nil {
		return fmt.Errorf(
			"rmapi.APIResponse.UnmarshalJSON: failed to decode %q: %w",
			APIResponseKeyExpires,
			err,
		)
	}
	resp.Path = m[APIResponseKeyPath]
	resp.URL = m[APIResponseKeyURL]
	resp.Method = m[APIResponseKeyMethod]
	resp.Expires = expires
	resp.Headers = make(map[string]string)
	for k, v := range m {
		if responseNonHeaderKeys.Contains(k) {
			continue
		}
		resp.Headers[k] = v
	}
	return nil
}
UnmarshalJSON implements json.Unmarshaler.
package rmapi
import (
	"bufio"
	"bytes"
	"context"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
	"go.yhsif.com/immutable"
	"go.yhsif.com/url2epub"
)
const (
	APIBase         = "https://rm-blob-storage-prod.appspot.com/api/v1"
	APIDownload     = APIBase + "/signed-urls/downloads"
	APIUpload       = APIBase + "/signed-urls/uploads"
	APISyncComplete = APIBase + "/sync-complete"
	IndexFileFirstMagic    = "3"
	RootEntryUnused1Magic  = "80000000"
	IndexEntryUnused1Magic = "0"
	HeaderRootGeneration = "x-goog-generation"
	NumEntrySplit = 5
	GCSPathBytes  = 32
)
type APIRequest struct {
	Method string `json:"http_method"`
	Path   string `json:"relative_path"`
	Generation string `json:"generatio,omitempty"`
}
type APIResponse struct {
	Path    string
	URL     string
	Method  string
	Expires time.Time
	Headers map[string]string
}
var _ json.Unmarshaler = (*APIResponse)(nil)
const (
	APIResponseKeyPath    = "relative_path"
	APIResponseKeyURL     = "url"
	APIResponseKeyMethod  = "method"
	APIResponseKeyExpires = "expires"
)
var responseNonHeaderKeys = immutable.SetLiteral(
	APIResponseKeyPath,
	APIResponseKeyURL,
	APIResponseKeyMethod,
	APIResponseKeyExpires,
)