From 81e8bbe63cba87d8953050f13f4252863ec5527a Mon Sep 17 00:00:00 2001
From: Simon Zolin <s.zolin@adguard.com>
Date: Tue, 12 Nov 2019 15:36:17 +0300
Subject: [PATCH] * /control/querylog_config: support optional parameters

---
 go.mod                |  2 +-
 go.sum                |  2 ++
 querylog/qlog.go      | 12 ++++--------
 querylog/qlog_http.go | 24 +++++++++++++++---------
 4 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/go.mod b/go.mod
index 51a1c692..0c5d90dc 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.12
 
 require (
 	github.com/AdguardTeam/dnsproxy v0.19.6
-	github.com/AdguardTeam/golibs v0.2.4
+	github.com/AdguardTeam/golibs v0.3.0
 	github.com/AdguardTeam/urlfilter v0.6.1
 	github.com/NYTimes/gziphandler v1.1.1
 	github.com/etcd-io/bbolt v1.3.3
diff --git a/go.sum b/go.sum
index a999a567..065a1622 100644
--- a/go.sum
+++ b/go.sum
@@ -4,6 +4,8 @@ github.com/AdguardTeam/golibs v0.1.3 h1:hmapdTtMtIk3T8eQDwTOLdqZLGDKNKk9325uC8z1
 github.com/AdguardTeam/golibs v0.1.3/go.mod h1:b0XkhgIcn2TxwX6C5AQMtpIFAgjPehNgxJErWkwA3ko=
 github.com/AdguardTeam/golibs v0.2.4 h1:GUssokegKxKF13K67Pgl0ZGwqHjNN6X7sep5ik6ORdY=
 github.com/AdguardTeam/golibs v0.2.4/go.mod h1:R3M+mAg3nWG4X4Hsag5eef/TckHFH12ZYhK7AzJc8+U=
+github.com/AdguardTeam/golibs v0.3.0 h1:1zO8ulGEOdXDDM++Ap4sYfTsT/Z4tZBZtiWSA4ykcOU=
+github.com/AdguardTeam/golibs v0.3.0/go.mod h1:R3M+mAg3nWG4X4Hsag5eef/TckHFH12ZYhK7AzJc8+U=
 github.com/AdguardTeam/urlfilter v0.6.1 h1:JX3gNYmgD9TCWE+G0C4MOn8WHYLAoVt0agltSvfldkY=
 github.com/AdguardTeam/urlfilter v0.6.1/go.mod h1:y+XdxBdbRG9v7pfjznlvv4Ufi2HTG8D0YMqR22OVy0Y=
 github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
diff --git a/querylog/qlog.go b/querylog/qlog.go
index 713a2849..07b8cd5c 100644
--- a/querylog/qlog.go
+++ b/querylog/qlog.go
@@ -26,7 +26,8 @@ const (
 
 // queryLog is a structure that writes and reads the DNS query log
 type queryLog struct {
-	conf    Config
+	conf    *Config
+	lock    sync.Mutex
 	logFile string // path to the log file
 
 	bufferLock    sync.RWMutex
@@ -40,7 +41,8 @@ type queryLog struct {
 func newQueryLog(conf Config) *queryLog {
 	l := queryLog{}
 	l.logFile = filepath.Join(conf.BaseDir, queryLogFileName)
-	l.conf = conf
+	l.conf = &Config{}
+	*l.conf = conf
 	if !checkInterval(l.conf.Interval) {
 		l.conf.Interval = 1
 	}
@@ -59,12 +61,6 @@ func checkInterval(days uint32) bool {
 	return days == 1 || days == 7 || days == 30 || days == 90
 }
 
-// Set new configuration at runtime
-func (l *queryLog) configure(conf Config) {
-	l.conf.Enabled = conf.Enabled
-	l.conf.Interval = conf.Interval
-}
-
 func (l *queryLog) WriteDiskConfig(dc *DiskConfig) {
 	dc.Enabled = l.conf.Enabled
 	dc.Interval = l.conf.Interval
diff --git a/querylog/qlog_http.go b/querylog/qlog_http.go
index d9feb9b6..07a3aadd 100644
--- a/querylog/qlog_http.go
+++ b/querylog/qlog_http.go
@@ -6,6 +6,7 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/AdguardTeam/golibs/jsonutil"
 	"github.com/AdguardTeam/golibs/log"
 	"github.com/miekg/dns"
 )
@@ -129,24 +130,29 @@ func (l *queryLog) handleQueryLogInfo(w http.ResponseWriter, r *http.Request) {
 
 // Set configuration
 func (l *queryLog) handleQueryLogConfig(w http.ResponseWriter, r *http.Request) {
-
-	reqData := qlogConfig{}
-	err := json.NewDecoder(r.Body).Decode(&reqData)
+	d := qlogConfig{}
+	req, err := jsonutil.DecodeObject(&d, r.Body)
 	if err != nil {
-		httpError(r, w, http.StatusBadRequest, "json decode: %s", err)
+		httpError(r, w, http.StatusBadRequest, "%s", err)
 		return
 	}
 
-	if !checkInterval(reqData.Interval) {
+	if req.Exists("interval") && !checkInterval(d.Interval) {
 		httpError(r, w, http.StatusBadRequest, "Unsupported interval")
 		return
 	}
 
-	conf := Config{
-		Enabled:  reqData.Enabled,
-		Interval: reqData.Interval,
+	l.lock.Lock()
+	// copy data, modify it, then activate.  Other threads (readers) don't need to use this lock.
+	conf := *l.conf
+	if req.Exists("enabled") {
+		conf.Enabled = d.Enabled
 	}
-	l.configure(conf)
+	if req.Exists("interval") {
+		conf.Interval = d.Interval
+	}
+	l.conf = &conf
+	l.lock.Unlock()
 
 	l.conf.ConfigModified()
 }