package webmail import ( "compress/gzip" "compress/zlib" "fmt" "github.com/mailru/easyjson" "golang.org/x/net/html/charset" "io" "net/http" "net/url" "strings" "time" ) type client struct { http *http.Client endpoint string } func NewClient(endpoint string, timeout time.Duration) Client { t := http.DefaultTransport.(*http.Transport) t.Proxy = http.ProxyFromEnvironment cli := &client{ endpoint: endpoint, http: &http.Client{ Transport: t, Timeout: timeout, }, } return cli } func (cli *client) Close() error { return nil } func (cli *client) CreateAlias(alias string) error { return cli.action(CreateAlias, alias) } func (cli *client) RemoveAlias(alias string) error { return cli.action(RemoveAlias, alias) } func (cli *client) action(e Action, alias string) error { alias = strings.TrimSpace(alias) if alias == "" { return fmt.Errorf("illegal arguments: alias must not be an empty string") } var ( d []byte result = new(Result) err error ) if d, err = cli.do(e, alias); err != nil { return err } if err = easyjson.Unmarshal(d, result); err != nil { return err } var errNo int64 if errNo, err = result.Error.Int64(); err != nil { return err } if result.Ok != "ok" || errNo > 0 { return fmt.Errorf("got unexpected result: `%s`", string(d)) } return nil } func (cli *client) ListAliases() ([]string, error) { var ( d []byte result = ResultList{} err error ) if d, err = cli.do(ListAliases, ""); err != nil { return nil, err } if err = easyjson.Unmarshal(d, &result); err != nil { return nil, err } return result, nil } func (cli *client) do(action Action, alias string) ([]byte, error) { var ( request *http.Request response *http.Response err error ) values := url.Values{} values.Set("act", string(action)) if ListAliases != action { values.Set("alias", alias) } if request, err = http.NewRequest(http.MethodPost, cli.endpoint, strings.NewReader(values.Encode())); err != nil { return nil, err } request.Header.Add("Content-Type", "application/x-www-form-urlencoded") if response, err = cli.http.Do(request); err != nil { return nil, err } if response.StatusCode < 200 || response.StatusCode > 299 { return nil, fmt.Errorf("got unexpected http status code [%d] %s", response.StatusCode, response.Status) } if response.ContentLength != -1 && response.ContentLength < 1 { return nil, nil } var ( contentEncoding = response.Header.Get("Content-Encoding") contentType = response.Header.Get("Content-Type") contentReader io.Reader = response.Body ) if "gzip" == contentEncoding { if r, err := gzip.NewReader(response.Body); err == nil { defer r.Close() contentReader = r } } else if "deflate" == contentEncoding { if r, err := zlib.NewReader(response.Body); err == nil { defer r.Close() contentReader = r } } if "application/octet-stream" != contentType { if r, err := charset.NewReader(contentReader, contentType); err == nil { contentReader = r } else { return nil, err } } return io.ReadAll(contentReader) }