mirror of
				https://github.com/tobychui/zoraxy.git
				synced 2025-10-31 22:14:07 +01:00 
			
		
		
		
	Add option to disable request logging per endpoint
This commit is contained in:
		| @@ -48,7 +48,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	//Check if this is a redirection url | ||||
| 	if h.Parent.Option.RedirectRuleTable.IsRedirectable(r) { | ||||
| 		statusCode := h.Parent.Option.RedirectRuleTable.HandleRedirect(w, r) | ||||
| 		h.Parent.logRequest(r, statusCode != 500, statusCode, "redirect", r.Host, "") | ||||
| 		h.Parent.logRequest(r, statusCode != 500, statusCode, "redirect", r.Host, "", nil) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -70,7 +70,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 			//Use default rule | ||||
| 			ruleID = "default" | ||||
| 		} | ||||
| 		if h.handleAccessRouting(ruleID, w, r) { | ||||
| 		if h.handleAccessRouting(ruleID, w, r, sep) { | ||||
| 			//Request handled by subroute | ||||
| 			return | ||||
| 		} | ||||
| @@ -79,7 +79,9 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 		if sep.RequireRateLimit { | ||||
| 			err := h.handleRateLimitRouting(w, r, sep) | ||||
| 			if err != nil { | ||||
| 				if !sep.DisableLogging { | ||||
| 					h.Parent.Option.Logger.LogHTTPRequest(r, "host", 307, r.Host, "") | ||||
| 				} | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| @@ -109,7 +111,9 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 			if potentialProxtEndpoint != nil && !potentialProxtEndpoint.Disabled { | ||||
| 				//Missing tailing slash. Redirect to target proxy endpoint | ||||
| 				http.Redirect(w, r, r.RequestURI+"/", http.StatusTemporaryRedirect) | ||||
| 				if !sep.DisableLogging { | ||||
| 					h.Parent.Option.Logger.LogHTTPRequest(r, "redirect", 307, r.Host, "") | ||||
| 				} | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| @@ -124,7 +128,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	*/ | ||||
|  | ||||
| 	//Root access control based on default rule | ||||
| 	blocked := h.handleAccessRouting("default", w, r) | ||||
| 	blocked := h.handleAccessRouting("default", w, r, h.Parent.Root) | ||||
| 	if blocked { | ||||
| 		return | ||||
| 	} | ||||
| @@ -210,19 +214,19 @@ func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request) | ||||
| 		} | ||||
| 		hostname := parsedURL.Hostname() | ||||
| 		if hostname == domainOnly { | ||||
| 			h.Parent.logRequest(r, false, 500, "root-redirect", domainOnly, "") | ||||
| 			h.Parent.logRequest(r, false, 500, "root-redirect", domainOnly, "", h.Parent.Root) | ||||
| 			http.Error(w, "Loopback redirects due to invalid settings", 500) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		h.Parent.logRequest(r, false, 307, "root-redirect", domainOnly, "") | ||||
| 		h.Parent.logRequest(r, false, 307, "root-redirect", domainOnly, "", h.Parent.Root) | ||||
| 		http.Redirect(w, r, redirectTarget, http.StatusTemporaryRedirect) | ||||
| 	case DefaultSite_NotFoundPage: | ||||
| 		//Serve the not found page, use template if exists | ||||
| 		h.serve404PageWithTemplate(w, r) | ||||
| 	case DefaultSite_NoResponse: | ||||
| 		//No response. Just close the connection | ||||
| 		h.Parent.logRequest(r, false, 444, "root-no_resp", domainOnly, "") | ||||
| 		h.Parent.logRequest(r, false, 444, "root-no_resp", domainOnly, "", h.Parent.Root) | ||||
| 		hijacker, ok := w.(http.Hijacker) | ||||
| 		if !ok { | ||||
| 			w.WriteHeader(http.StatusNoContent) | ||||
| @@ -236,11 +240,11 @@ func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request) | ||||
| 		conn.Close() | ||||
| 	case DefaultSite_TeaPot: | ||||
| 		//I'm a teapot | ||||
| 		h.Parent.logRequest(r, false, 418, "root-teapot", domainOnly, "") | ||||
| 		h.Parent.logRequest(r, false, 418, "root-teapot", domainOnly, "", h.Parent.Root) | ||||
| 		http.Error(w, "I'm a teapot", http.StatusTeapot) | ||||
| 	default: | ||||
| 		//Unknown routing option. Send empty response | ||||
| 		h.Parent.logRequest(r, false, 544, "root-unknown", domainOnly, "") | ||||
| 		h.Parent.logRequest(r, false, 544, "root-unknown", domainOnly, "", h.Parent.Root) | ||||
| 		http.Error(w, "544 - No Route Defined", 544) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ import ( | ||||
|  | ||||
| // Handle access check (blacklist / whitelist), return true if request is handled (aka blocked) | ||||
| // if the return value is false, you can continue process the response writer | ||||
| func (h *ProxyHandler) handleAccessRouting(ruleID string, w http.ResponseWriter, r *http.Request) bool { | ||||
| func (h *ProxyHandler) handleAccessRouting(ruleID string, w http.ResponseWriter, r *http.Request, sep *ProxyEndpoint) bool { | ||||
| 	accessRule, err := h.Parent.Option.AccessController.GetAccessRuleByID(ruleID) | ||||
| 	if err != nil { | ||||
| 		//Unable to load access rule. Target rule not found? | ||||
| @@ -25,7 +25,7 @@ func (h *ProxyHandler) handleAccessRouting(ruleID string, w http.ResponseWriter, | ||||
|  | ||||
| 	isBlocked, blockedReason := accessRequestBlocked(accessRule, h.Parent.Option.WebDirectory, w, r) | ||||
| 	if isBlocked { | ||||
| 		h.Parent.logRequest(r, false, 403, blockedReason, r.Host, "") | ||||
| 		h.Parent.logRequest(r, false, 403, blockedReason, r.Host, "", sep) | ||||
| 	} | ||||
| 	return isBlocked | ||||
| } | ||||
|   | ||||
| @@ -156,7 +156,7 @@ func (router *Router) StartProxyService() error { | ||||
| 						if err != nil { | ||||
| 							http.ServeFile(w, r, "./web/hosterror.html") | ||||
| 							router.Option.Logger.PrintAndLog("dprouter", "failed to get upstream for hostname", err) | ||||
| 							router.logRequest(r, false, 404, "vdir-http", r.Host, "") | ||||
| 							router.logRequest(r, false, 404, "vdir-http", r.Host, "", sep) | ||||
| 						} | ||||
|  | ||||
| 						endpointProxyRewriteRules := GetDefaultHeaderRewriteRules() | ||||
|   | ||||
| @@ -141,7 +141,7 @@ func (h *ProxyHandler) upstreamHostSwap(w http.ResponseWriter, r *http.Request, | ||||
| 		} else { | ||||
| 			//Endpoint disabled, return 503 | ||||
| 			http.ServeFile(w, r, "./web/rperror.html") | ||||
| 			h.Parent.logRequest(r, false, 521, "host-http", r.Host, upstreamHostname) | ||||
| 			h.Parent.logRequest(r, false, 521, "host-http", r.Host, upstreamHostname, currentTarget) | ||||
| 		} | ||||
| 		return true | ||||
| 	} | ||||
| @@ -159,7 +159,7 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe | ||||
| 	if err != nil { | ||||
| 		http.ServeFile(w, r, "./web/rperror.html") | ||||
| 		h.Parent.Option.Logger.PrintAndLog("proxy", "Failed to assign an upstream for this request", err) | ||||
| 		h.Parent.logRequest(r, false, 521, "subdomain-http", r.URL.Hostname(), r.Host) | ||||
| 		h.Parent.logRequest(r, false, 521, "subdomain-http", r.URL.Hostname(), r.Host, target) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -187,7 +187,7 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe | ||||
| 		if selectedUpstream.RequireTLS { | ||||
| 			u, _ = url.Parse("wss://" + wsRedirectionEndpoint + requestURL) | ||||
| 		} | ||||
| 		h.Parent.logRequest(r, true, 101, "host-websocket", reqHostname, selectedUpstream.OriginIpOrDomain) | ||||
| 		h.Parent.logRequest(r, true, 101, "host-websocket", reqHostname, selectedUpstream.OriginIpOrDomain, target) | ||||
|  | ||||
| 		if target.HeaderRewriteRules == nil { | ||||
| 			target.HeaderRewriteRules = GetDefaultHeaderRewriteRules() | ||||
| @@ -249,18 +249,18 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe | ||||
| 	if err != nil { | ||||
| 		if errors.As(err, &dnsError) { | ||||
| 			http.ServeFile(w, r, "./web/hosterror.html") | ||||
| 			h.Parent.logRequest(r, false, 404, "host-http", reqHostname, upstreamHostname) | ||||
| 			h.Parent.logRequest(r, false, 404, "host-http", reqHostname, upstreamHostname, target) | ||||
| 		} else if errors.Is(err, context.Canceled) { | ||||
| 			//Request canceled by client, usually due to manual refresh before page load | ||||
| 			http.Error(w, "Request canceled", http.StatusRequestTimeout) | ||||
| 			h.Parent.logRequest(r, false, http.StatusRequestTimeout, "host-http", reqHostname, upstreamHostname) | ||||
| 			h.Parent.logRequest(r, false, http.StatusRequestTimeout, "host-http", reqHostname, upstreamHostname, target) | ||||
| 		} else { | ||||
| 			http.ServeFile(w, r, "./web/rperror.html") | ||||
| 			h.Parent.logRequest(r, false, 521, "host-http", reqHostname, upstreamHostname) | ||||
| 			h.Parent.logRequest(r, false, 521, "host-http", reqHostname, upstreamHostname, target) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	h.Parent.logRequest(r, true, statusCode, "host-http", reqHostname, upstreamHostname) | ||||
| 	h.Parent.logRequest(r, true, statusCode, "host-http", reqHostname, upstreamHostname, target) | ||||
| } | ||||
|  | ||||
| // Handle vdir type request | ||||
| @@ -286,7 +286,7 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe | ||||
| 			target.parent.HeaderRewriteRules = GetDefaultHeaderRewriteRules() | ||||
| 		} | ||||
|  | ||||
| 		h.Parent.logRequest(r, true, 101, "vdir-websocket", r.Host, target.Domain) | ||||
| 		h.Parent.logRequest(r, true, 101, "vdir-websocket", r.Host, target.Domain, target.parent) | ||||
| 		wspHandler := websocketproxy.NewProxy(u, websocketproxy.Options{ | ||||
| 			SkipTLSValidation:  target.SkipCertValidations, | ||||
| 			SkipOriginCheck:    true,                                       //You should not use websocket via virtual directory. But keep this to true for compatibility | ||||
| @@ -342,19 +342,25 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe | ||||
| 		if errors.As(err, &dnsError) { | ||||
| 			http.ServeFile(w, r, "./web/hosterror.html") | ||||
| 			log.Println(err.Error()) | ||||
| 			h.Parent.logRequest(r, false, 404, "vdir-http", reqHostname, target.Domain) | ||||
| 			h.Parent.logRequest(r, false, 404, "vdir-http", reqHostname, target.Domain, target.parent) | ||||
| 		} else { | ||||
| 			http.ServeFile(w, r, "./web/rperror.html") | ||||
| 			log.Println(err.Error()) | ||||
| 			h.Parent.logRequest(r, false, 521, "vdir-http", reqHostname, target.Domain) | ||||
| 			h.Parent.logRequest(r, false, 521, "vdir-http", reqHostname, target.Domain, target.parent) | ||||
| 		} | ||||
| 	} | ||||
| 	h.Parent.logRequest(r, true, statusCode, "vdir-http", reqHostname, target.Domain) | ||||
| 	h.Parent.logRequest(r, true, statusCode, "vdir-http", reqHostname, target.Domain, target.parent) | ||||
|  | ||||
| } | ||||
|  | ||||
| // This logger collect data for the statistical analysis. For log to file logger, check the Logger and LogHTTPRequest handler | ||||
| func (router *Router) logRequest(r *http.Request, succ bool, statusCode int, forwardType string, originalHostname string, upstreamHostname string) { | ||||
| func (router *Router) logRequest(r *http.Request, succ bool, statusCode int, forwardType string, originalHostname string, upstreamHostname string, endpoint *ProxyEndpoint) { | ||||
| 	if endpoint != nil && endpoint.DisableLogging { | ||||
| 		// Notes: endpoint can be nil if the request has been handled before a host name can be resolved | ||||
| 		// e.g. Redirection matching rule | ||||
| 		// in that case we will log it by default and will not enter this routine | ||||
| 		return | ||||
| 	} | ||||
| 	if router.Option.StatisticCollector != nil { | ||||
| 		go func() { | ||||
| 			requestInfo := statistic.RequestInfo{ | ||||
|   | ||||
| @@ -51,7 +51,7 @@ func (t *RequestCountPerIpTable) Clear() { | ||||
| func (h *ProxyHandler) handleRateLimitRouting(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error { | ||||
| 	err := h.Parent.handleRateLimit(w, r, pe) | ||||
| 	if err != nil { | ||||
| 		h.Parent.logRequest(r, false, 429, "ratelimit", r.URL.Hostname(), "") | ||||
| 		h.Parent.logRequest(r, false, 429, "ratelimit", r.URL.Hostname(), "", pe) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|   | ||||
| @@ -208,6 +208,7 @@ type ProxyEndpoint struct { | ||||
|  | ||||
| 	//Uptime Monitor | ||||
| 	DisableUptimeMonitor bool //Disable uptime monitor for this endpoint | ||||
| 	DisableLogging       bool //Disable logging of reverse proxy requests | ||||
|  | ||||
| 	// Chunked Transfer Encoding | ||||
| 	DisableChunkedTransferEncoding bool //Disable chunked transfer encoding for this endpoint | ||||
|   | ||||
| @@ -244,6 +244,9 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) { | ||||
| 		enableUtm = true | ||||
| 	} | ||||
|  | ||||
| 	// Disable logging? | ||||
| 	disableLog, _ := utils.PostBool(r, "disableLog") | ||||
|  | ||||
| 	useBypassGlobalTLS := bypassGlobalTLS == "true" | ||||
|  | ||||
| 	//Enable TLS validation? | ||||
| @@ -416,6 +419,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) { | ||||
|  | ||||
| 			Tags:                 tags, | ||||
| 			DisableUptimeMonitor: !enableUtm, | ||||
| 			DisableLogging:       disableLog, | ||||
| 		} | ||||
|  | ||||
| 		preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisProxyEndpoint) | ||||
| @@ -570,6 +574,9 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) { | ||||
| 	// Disable chunked Encoding | ||||
| 	disableChunkedEncoding, _ := utils.PostBool(r, "dChunkedEnc") | ||||
|  | ||||
| 	// Disable logging | ||||
| 	disableLogging, _ := utils.PostBool(r, "dLogging") | ||||
|  | ||||
| 	//Load the previous basic auth credentials from current proxy rules | ||||
| 	targetProxyEntry, err := dynamicProxyRouter.LoadProxy(rootNameOrMatchingDomain) | ||||
| 	if err != nil { | ||||
| @@ -611,6 +618,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) { | ||||
| 	newProxyEndpoint.UseStickySession = useStickySession | ||||
| 	newProxyEndpoint.DisableUptimeMonitor = disbleUtm | ||||
| 	newProxyEndpoint.DisableChunkedTransferEncoding = disableChunkedEncoding | ||||
| 	newProxyEndpoint.DisableLogging = disableLogging | ||||
| 	newProxyEndpoint.Tags = tags | ||||
|  | ||||
| 	//Prepare to replace the current routing rule | ||||
|   | ||||
| @@ -284,6 +284,12 @@ | ||||
|                                     <label>Allow plain HTTP access<br> | ||||
|                                         <small>Allow inbound connections without TLS/SSL</small></label> | ||||
|                                 </div> | ||||
|                                 <br> | ||||
|                                 <div class="ui checkbox" style="margin-top: 0.4em;"> | ||||
|                                     <input type="checkbox" class="DisableLogging"> | ||||
|                                     <label>Disable Requests Logging<br> | ||||
|                                         <small>Disable logging for all incoming requests for this hostname</small></label> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                             | ||||
|                         </div> | ||||
| @@ -885,6 +891,7 @@ | ||||
|         let rateLimit = $(editor).find(".RateLimit").val(); | ||||
|         let bypassGlobalTLS = $(editor).find(".BypassGlobalTLS")[0].checked; | ||||
|         let disableChunkedTransferEncoding = $(editor).find(".DisableChunkedTransferEncoding")[0].checked; | ||||
|         let disableLogging = $(editor).find(".DisableLogging")[0].checked; | ||||
|         let tags = getTagsArrayFromEndpoint(uuid); | ||||
|         if (tags.length > 0){ | ||||
|             tags = tags.join(","); | ||||
| @@ -901,6 +908,7 @@ | ||||
|                 "authprovider" :authProviderType, | ||||
|                 "rate" :requireRateLimit, | ||||
|                 "dChunkedEnc": disableChunkedTransferEncoding, | ||||
|                 "dLogging": disableLogging, | ||||
|                 "ratenum" :rateLimit, | ||||
|                 "tags": tags, | ||||
|             }; | ||||
| @@ -1239,6 +1247,12 @@ | ||||
|             saveProxyInlineEdit(uuid); | ||||
|         }); | ||||
|  | ||||
|         editor.find(".DisableLogging").off('change'); | ||||
|         editor.find(".DisableLogging").prop("checked", subd.DisableLogging); | ||||
|         editor.find(".DisableLogging").on("change", function() { | ||||
|             saveProxyInlineEdit(uuid); | ||||
|         }); | ||||
|          | ||||
|         //Bind the edit button | ||||
|         editor.find(".downstream_primary_hostname_edit_btn").off("click").on("click", function(){ | ||||
|             editor.find(".downstream_primary_hostname_edit_btn").parent().hide(); | ||||
|   | ||||
| @@ -70,6 +70,13 @@ | ||||
|                                         </label> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="field"> | ||||
|                                     <div class="ui checkbox"> | ||||
|                                         <input type="checkbox" id="disableLog"> | ||||
|                                         <label>Disable Requests Logging<br><small>Disable requests logging for this host, recommended for high traffic sites</small> | ||||
|                                         </label> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="field"> | ||||
|                                     <label>Tags</label> | ||||
|                                     <input type="text" id="proxyTags" placeholder="e.g. mediaserver, management"> | ||||
| @@ -268,6 +275,7 @@ | ||||
|         let useStickySessionLB = $("#useStickySessionLB")[0].checked;  | ||||
|         let tags = $("#proxyTags").val().trim(); | ||||
|         let enableUtm = $("#enableUtm")[0].checked; | ||||
|         let disableLog = $("#disableLog")[0].checked; | ||||
|  | ||||
|         if (rootname.trim() == ""){ | ||||
|             $("#rootname").parent().addClass("error"); | ||||
| @@ -303,6 +311,7 @@ | ||||
|                 stickysess: useStickySessionLB, | ||||
|                 tags: tags, | ||||
|                 enableUtm: enableUtm, | ||||
|                 disableLog: disableLog, | ||||
|             }, | ||||
|             success: function(data){ | ||||
|                 if (data.error != undefined){ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Toby Chui
					Toby Chui