aboutsummaryrefslogtreecommitdiff
path: root/internal/http
diff options
context:
space:
mode:
authorRené 'Necoro' Neumann <necoro@necoro.eu>2020-05-04 15:31:46 +0200
committerRené 'Necoro' Neumann <necoro@necoro.eu>2020-05-04 15:31:46 +0200
commite2322c799ae0a05ed2b7eb63bffebbe0b54b292f (patch)
tree9f72634c0f1525a514caa7d51e33c4dc8b5a137f /internal/http
parent44f53f5956216cdd52ad58d6e666013a8f202967 (diff)
downloadfeed2imap-go-e2322c799ae0a05ed2b7eb63bffebbe0b54b292f.tar.gz
feed2imap-go-e2322c799ae0a05ed2b7eb63bffebbe0b54b292f.tar.bz2
feed2imap-go-e2322c799ae0a05ed2b7eb63bffebbe0b54b292f.zip
Unify connection handling
Diffstat (limited to '')
-rw-r--r--internal/http/client.go88
1 files changed, 88 insertions, 0 deletions
diff --git a/internal/http/client.go b/internal/http/client.go
new file mode 100644
index 0000000..c9af26e
--- /dev/null
+++ b/internal/http/client.go
@@ -0,0 +1,88 @@
+package http
+
+import (
+ ctxt "context"
+ "crypto/tls"
+ "fmt"
+ "net/http"
+ "time"
+)
+
+// share HTTP clients
+var (
+ stdClient *http.Client
+ unsafeClient *http.Client
+)
+
+// Error represents an HTTP error returned by a server.
+type Error struct {
+ StatusCode int
+ Status string
+}
+
+func (err Error) Error() string {
+ return fmt.Sprintf("http error: %s", err.Status)
+}
+
+func init() {
+ // std
+ stdClient = &http.Client{Transport: http.DefaultTransport}
+
+ // unsafe
+ tlsConfig := &tls.Config{InsecureSkipVerify: true}
+ transport := http.DefaultTransport.(*http.Transport).Clone()
+ transport.TLSClientConfig = tlsConfig
+ unsafeClient = &http.Client{Transport: transport}
+}
+
+func context(timeout int) (ctxt.Context, ctxt.CancelFunc) {
+ return ctxt.WithTimeout(ctxt.Background(), time.Duration(timeout)*time.Second)
+}
+
+func client(disableTLS bool) *http.Client {
+ if disableTLS {
+ return unsafeClient
+ }
+ return stdClient
+}
+
+var noop ctxt.CancelFunc = func() {}
+
+func Get(url string, timeout int, disableTLS bool) (resp *http.Response, cancel ctxt.CancelFunc, err error) {
+ prematureExit := true
+ ctx, ctxCancel := context(timeout)
+
+ cancel = func() {
+ if resp != nil {
+ _ = resp.Body.Close()
+ }
+ ctxCancel()
+ }
+
+ defer func() {
+ if prematureExit {
+ cancel()
+ }
+ }()
+
+ req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
+ if err != nil {
+ return nil, noop, err
+ }
+ req.Header.Set("User-Agent", "Feed2Imap-Go/1.0")
+
+ resp, err = client(disableTLS).Do(req)
+ if err != nil {
+ return nil, noop, err
+ }
+
+ if resp.StatusCode < 200 || resp.StatusCode >= 300 {
+ return nil, noop, Error{
+ StatusCode: resp.StatusCode,
+ Status: resp.Status,
+ }
+ }
+
+ prematureExit = false
+ return resp, cancel, nil
+}
store.sh?h=1.6&id=ac045fe4254306fbcc32ffce058b860d5a473b98&follow=1'>Abstract remove empty directories into function.Jason A. Donenfeld1-14/+11 2014-04-18Remember to prune empty folders.Jason A. Donenfeld1-0/+8 2014-04-18init: allow deinitializationJason A. Donenfeld2-2/+18 2014-04-18bash-completion: filter dot files from resultsJason A. Donenfeld1-3/+8 2014-04-18reencrypt: remove option, do automaticallyJason A. Donenfeld5-39/+25 2014-04-18reencryption: add to completion filesJason A. Donenfeld3-1/+5 2014-04-18Specify variable gpg.Jason A. Donenfeld1-1/+1 2014-04-18style: don't escape new line on &&Jason A. Donenfeld1-2/+2 2014-04-18reencryption: remove temporary file on failureJason A. Donenfeld1-1/+1 2014-04-18reencryption: only reencrypt files when requiredJason A. Donenfeld2-16/+37 2014-04-17cp: typo as cvJason A. Donenfeld1-1/+1 2014-04-17bash: gpg_id is localJason A. Donenfeld1-0/+1 2014-04-17move/copy: always reencrypt passwords at destinationJason A. Donenfeld5-25/+56 2014-04-17makefile: allow platform files with gnu sedJason A. Donenfeld1-7/+8 2014-04-17mv: Add pass mv/rename supportJason A. Donenfeld5-3/+78 2014-04-17revelation2pass: add plain XML importJavali1-11/+15 2014-04-17platform: add cygwin supportJason A. Donenfeld2-1/+17