aboutsummaryrefslogtreecommitdiff
path: root/internal/qna
diff options
context:
space:
mode:
Diffstat (limited to 'internal/qna')
-rw-r--r--internal/qna/qna.go109
1 files changed, 108 insertions, 1 deletions
diff --git a/internal/qna/qna.go b/internal/qna/qna.go
index bd2078d..809df15 100644
--- a/internal/qna/qna.go
+++ b/internal/qna/qna.go
@@ -1,12 +1,119 @@
package qna
+import (
+ "fmt"
+ "net"
+ "net/url"
+)
+
type Question struct {
Domain string // domain name to visit via HTTPS
}
type Answer struct {
Domain string // domain name of the visited HTTPS site
- OK bool // true if HTTP GET request succeeded
HTTP string // value set in the Onion-Location HTTP header (if any)
HTML string // value set in the Onion-Location HTML attribute (if any)
+
+ ReqErr error // nil if HTTP GET request could be constructed
+ DoErr error // nil if HTTP GET request could be executed
+}
+
+func (a Answer) String() string {
+ if a.ReqErr != nil {
+ return fmt.Sprintf("%s: %v", a.ReqErr)
+ }
+ if a.DoErr != nil {
+ return fmt.Sprintf("%s: %v", a.DoErr)
+ }
+ if a.HTTP == "" && a.HTML == "" {
+ return fmt.Sprintf("%s: connected but found no Onion-Location")
+ }
+ return fmt.Sprintf("%s header=%s attribute=%s", a.Domain, a.HTTP, a.HTML)
+}
+
+type Progress struct {
+ NumReqErr int // error before sending requests
+ NumDoErr int // error while sending request
+ NumOK int // got response
+ NumOnion int // found onion in response
+
+ // More details about DNS errors while sending request
+ NumDNSNotFound int
+ NumDNSTimeout int
+ NumDNSOther int
+}
+
+func (p Progress) String() string {
+ str := fmt.Sprintf(" Processed: %d\n", p.NumAnswer())
+ str += fmt.Sprintf(" Success: %d (Onion-Location:%d)\n", p.NumOK, p.NumOnion)
+ str += fmt.Sprintf(" Failure: %d (Req:%d Do:%d)\n", p.NumError(), p.NumReqErr, p.NumDoErr)
+ str += fmt.Sprintf(" DNS: %d (NotFound:%d Timeout:%d Other:%d)",
+ p.NumDNSErr(), p.NumDNSNotFound, p.NumDNSTimeout, p.NumDNSOther)
+ return str
+}
+
+func (p *Progress) NumAnswer() int {
+ return p.NumReqErr + p.NumDoErr + p.NumOK
+}
+
+func (p *Progress) NumError() int {
+ return p.NumReqErr + p.NumDoErr
+}
+
+func (p *Progress) NumDNSErr() int {
+ return p.NumDNSNotFound + p.NumDNSTimeout + p.NumDNSOther
+}
+
+func (p *Progress) AddAnswer(a Answer) {
+ if a.ReqErr != nil {
+ p.NumReqErr += 1
+ return
+ }
+ if a.DoErr != nil {
+ p.NumDoErr += 1
+ err := dnsError(a.DoErr)
+ if err == nil {
+ return
+ }
+
+ if err.IsTimeout {
+ p.NumDNSTimeout += 1
+ } else if err.IsNotFound {
+ p.NumDNSNotFound += 1
+ } else {
+ p.NumDNSOther += 1
+ }
+ return
+ }
+
+ p.NumOK += 1
+ if a.HTTP != "" || a.HTML != "" {
+ p.NumOnion += 1
+ }
+}
+
+func dnsError(err error) *net.DNSError {
+ if err == nil {
+ return nil
+ }
+
+ urlErr, ok := err.(*url.Error)
+ if !ok {
+ return nil
+ }
+
+ err = urlErr.Err
+ opErr, ok := err.(*net.OpError)
+ if !ok {
+ return nil
+ }
+
+ err = opErr.Err
+ dnsErr, ok := err.(*net.DNSError)
+ if !ok {
+ return nil
+ }
+
+ return dnsErr
}