mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-04 22:57:20 +02:00
v3.0.5 init commit
+ Added external domain name detection for PR #168 + Updated uptime error message in 5xx range + Modernized reverse proxy error page template + Added wip permission policy module
This commit is contained in:
parent
6feb2d105d
commit
d596d6b843
@ -52,7 +52,7 @@ var logOutputToFile = flag.Bool("log", true, "Log terminal output to file")
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
name = "Zoraxy"
|
name = "Zoraxy"
|
||||||
version = "3.0.4"
|
version = "3.0.5"
|
||||||
nodeUUID = "generic"
|
nodeUUID = "generic"
|
||||||
development = false //Set this to false to use embedded web fs
|
development = false //Set this to false to use embedded web fs
|
||||||
bootTime = time.Now().Unix()
|
bootTime = time.Now().Unix()
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReverseProxy is an HTTP Handler that takes an incoming request and
|
// ReverseProxy is an HTTP Handler that takes an incoming request and
|
||||||
@ -346,8 +348,11 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
|
|||||||
p.Director(outreq)
|
p.Director(outreq)
|
||||||
outreq.Close = false
|
outreq.Close = false
|
||||||
|
|
||||||
// Always use the original host, see issue #164
|
//Only skip origin rewrite iff proxy target require TLS and it is external domain name like github.com
|
||||||
outreq.Host = rrr.OriginalHost
|
if !(rrr.UseTLS && isExternalDomainName(rrr.ProxyDomain)) {
|
||||||
|
// Always use the original host, see issue #164
|
||||||
|
outreq.Host = rrr.OriginalHost
|
||||||
|
}
|
||||||
|
|
||||||
// We may modify the header (shallow copied above), so we only copy it.
|
// We may modify the header (shallow copied above), so we only copy it.
|
||||||
outreq.Header = make(http.Header)
|
outreq.Header = make(http.Header)
|
||||||
@ -424,6 +429,10 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
|
|||||||
// Copy header from response to client.
|
// Copy header from response to client.
|
||||||
copyHeader(rw.Header(), res.Header)
|
copyHeader(rw.Header(), res.Header)
|
||||||
|
|
||||||
|
// inject permission policy headers
|
||||||
|
//TODO: Load permission policy from rrr
|
||||||
|
permissionpolicy.InjectPermissionPolicyHeader(rw, nil)
|
||||||
|
|
||||||
// The "Trailer" header isn't included in the Transport's response, Build it up from Trailer.
|
// The "Trailer" header isn't included in the Transport's response, Build it up from Trailer.
|
||||||
if len(res.Trailer) > 0 {
|
if len(res.Trailer) > 0 {
|
||||||
trailerKeys := make([]string, 0, len(res.Trailer))
|
trailerKeys := make([]string, 0, len(res.Trailer))
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package dpcore
|
package dpcore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -60,3 +61,34 @@ func replaceLocationHost(urlString string, rrr *ResponseRewriteRuleSet, useTLS b
|
|||||||
func ReplaceLocationHost(urlString string, rrr *ResponseRewriteRuleSet, useTLS bool) (string, error) {
|
func ReplaceLocationHost(urlString string, rrr *ResponseRewriteRuleSet, useTLS bool) (string, error) {
|
||||||
return replaceLocationHost(urlString, rrr, useTLS)
|
return replaceLocationHost(urlString, rrr, useTLS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isExternalDomainName check and return if the hostname is external domain name (e.g. github.com)
|
||||||
|
// instead of internal (like 192.168.1.202:8443 (ip address) or domains end with .local or .internal)
|
||||||
|
func isExternalDomainName(hostname string) bool {
|
||||||
|
host, _, err := net.SplitHostPort(hostname)
|
||||||
|
if err != nil {
|
||||||
|
//hostname doesnt contain port
|
||||||
|
ip := net.ParseIP(hostname)
|
||||||
|
if ip != nil {
|
||||||
|
//IP address, not a domain name
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Hostname contain port, use hostname without port to check if it is ip
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip != nil {
|
||||||
|
//IP address, not a domain name
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if it is internal DNS assigned domains
|
||||||
|
internalDNSTLD := []string{".local", ".internal", ".localhost", ".home.arpa"}
|
||||||
|
for _, tld := range internalDNSTLD {
|
||||||
|
if strings.HasSuffix(strings.ToLower(hostname), tld) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
193
src/mod/dynamicproxy/permissionpolicy/permissionpolicy.go
Normal file
193
src/mod/dynamicproxy/permissionpolicy/permissionpolicy.go
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
package permissionpolicy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Permisson Policy
|
||||||
|
|
||||||
|
This is a permission policy header modifier that changes
|
||||||
|
the request permission related policy fields
|
||||||
|
|
||||||
|
author: tobychui
|
||||||
|
*/
|
||||||
|
|
||||||
|
type PermissionsPolicy struct {
|
||||||
|
Accelerometer []string `json:"accelerometer"`
|
||||||
|
AmbientLightSensor []string `json:"ambient_light_sensor"`
|
||||||
|
Autoplay []string `json:"autoplay"`
|
||||||
|
Battery []string `json:"battery"`
|
||||||
|
Camera []string `json:"camera"`
|
||||||
|
CrossOriginIsolated []string `json:"cross_origin_isolated"`
|
||||||
|
DisplayCapture []string `json:"display_capture"`
|
||||||
|
DocumentDomain []string `json:"document_domain"`
|
||||||
|
EncryptedMedia []string `json:"encrypted_media"`
|
||||||
|
ExecutionWhileNotRendered []string `json:"execution_while_not_rendered"`
|
||||||
|
ExecutionWhileOutOfView []string `json:"execution_while_out_of_viewport"`
|
||||||
|
Fullscreen []string `json:"fullscreen"`
|
||||||
|
Geolocation []string `json:"geolocation"`
|
||||||
|
Gyroscope []string `json:"gyroscope"`
|
||||||
|
KeyboardMap []string `json:"keyboard_map"`
|
||||||
|
Magnetometer []string `json:"magnetometer"`
|
||||||
|
Microphone []string `json:"microphone"`
|
||||||
|
Midi []string `json:"midi"`
|
||||||
|
NavigationOverride []string `json:"navigation_override"`
|
||||||
|
Payment []string `json:"payment"`
|
||||||
|
PictureInPicture []string `json:"picture_in_picture"`
|
||||||
|
PublicKeyCredentialsGet []string `json:"publickey_credentials_get"`
|
||||||
|
ScreenWakeLock []string `json:"screen_wake_lock"`
|
||||||
|
SyncXHR []string `json:"sync_xhr"`
|
||||||
|
USB []string `json:"usb"`
|
||||||
|
WebShare []string `json:"web_share"`
|
||||||
|
XRSpatialTracking []string `json:"xr_spatial_tracking"`
|
||||||
|
ClipboardRead []string `json:"clipboard_read"`
|
||||||
|
ClipboardWrite []string `json:"clipboard_write"`
|
||||||
|
Gamepad []string `json:"gamepad"`
|
||||||
|
SpeakerSelection []string `json:"speaker_selection"`
|
||||||
|
ConversionMeasurement []string `json:"conversion_measurement"`
|
||||||
|
FocusWithoutUserActivation []string `json:"focus_without_user_activation"`
|
||||||
|
HID []string `json:"hid"`
|
||||||
|
IdleDetection []string `json:"idle_detection"`
|
||||||
|
InterestCohort []string `json:"interest_cohort"`
|
||||||
|
Serial []string `json:"serial"`
|
||||||
|
SyncScript []string `json:"sync_script"`
|
||||||
|
TrustTokenRedemption []string `json:"trust_token_redemption"`
|
||||||
|
Unload []string `json:"unload"`
|
||||||
|
WindowPlacement []string `json:"window_placement"`
|
||||||
|
VerticalScroll []string `json:"vertical_scroll"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultPermissionPolicy returns a PermissionsPolicy struct with all policies set to *
|
||||||
|
func GetDefaultPermissionPolicy() *PermissionsPolicy {
|
||||||
|
return &PermissionsPolicy{
|
||||||
|
Accelerometer: []string{"*"},
|
||||||
|
AmbientLightSensor: []string{"*"},
|
||||||
|
Autoplay: []string{"*"},
|
||||||
|
Battery: []string{"*"},
|
||||||
|
Camera: []string{"*"},
|
||||||
|
CrossOriginIsolated: []string{"*"},
|
||||||
|
DisplayCapture: []string{"*"},
|
||||||
|
DocumentDomain: []string{"*"},
|
||||||
|
EncryptedMedia: []string{"*"},
|
||||||
|
ExecutionWhileNotRendered: []string{"*"},
|
||||||
|
ExecutionWhileOutOfView: []string{"*"},
|
||||||
|
Fullscreen: []string{"*"},
|
||||||
|
Geolocation: []string{"*"},
|
||||||
|
Gyroscope: []string{"*"},
|
||||||
|
KeyboardMap: []string{"*"},
|
||||||
|
Magnetometer: []string{"*"},
|
||||||
|
Microphone: []string{"*"},
|
||||||
|
Midi: []string{"*"},
|
||||||
|
NavigationOverride: []string{"*"},
|
||||||
|
Payment: []string{"*"},
|
||||||
|
PictureInPicture: []string{"*"},
|
||||||
|
PublicKeyCredentialsGet: []string{"*"},
|
||||||
|
ScreenWakeLock: []string{"*"},
|
||||||
|
SyncXHR: []string{"*"},
|
||||||
|
USB: []string{"*"},
|
||||||
|
WebShare: []string{"*"},
|
||||||
|
XRSpatialTracking: []string{"*"},
|
||||||
|
ClipboardRead: []string{"*"},
|
||||||
|
ClipboardWrite: []string{"*"},
|
||||||
|
Gamepad: []string{"*"},
|
||||||
|
SpeakerSelection: []string{"*"},
|
||||||
|
ConversionMeasurement: []string{"*"},
|
||||||
|
FocusWithoutUserActivation: []string{"*"},
|
||||||
|
HID: []string{"*"},
|
||||||
|
IdleDetection: []string{"*"},
|
||||||
|
InterestCohort: []string{"*"},
|
||||||
|
Serial: []string{"*"},
|
||||||
|
SyncScript: []string{"*"},
|
||||||
|
TrustTokenRedemption: []string{"*"},
|
||||||
|
Unload: []string{"*"},
|
||||||
|
WindowPlacement: []string{"*"},
|
||||||
|
VerticalScroll: []string{"*"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InjectPermissionPolicyHeader inject the permission policy into headers
|
||||||
|
func InjectPermissionPolicyHeader(w http.ResponseWriter, policy *PermissionsPolicy) {
|
||||||
|
//Keep the original Permission Policy if exists, or there are no policy given
|
||||||
|
if policy == nil || w.Header().Get("Permissions-Policy") != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
policyHeader := []string{}
|
||||||
|
|
||||||
|
// Helper function to add policy directives
|
||||||
|
addDirective := func(name string, sources []string) {
|
||||||
|
if len(sources) > 0 {
|
||||||
|
if sources[0] == "*" {
|
||||||
|
//Allow all
|
||||||
|
policyHeader = append(policyHeader, fmt.Sprintf("%s=%s", name, "*"))
|
||||||
|
} else {
|
||||||
|
//Other than "self" which do not need double quote, others domain need double quote in place
|
||||||
|
formatedSources := []string{}
|
||||||
|
for _, source := range sources {
|
||||||
|
if source == "self" {
|
||||||
|
formatedSources = append(formatedSources, "self")
|
||||||
|
} else {
|
||||||
|
formatedSources = append(formatedSources, "\""+source+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
policyHeader = append(policyHeader, fmt.Sprintf("%s=(%s)", name, strings.Join(formatedSources, " ")))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//There are no setting for this field. Assume no permission
|
||||||
|
policyHeader = append(policyHeader, fmt.Sprintf("%s=()", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add each policy directive to the header
|
||||||
|
addDirective("accelerometer", policy.Accelerometer)
|
||||||
|
addDirective("ambient-light-sensor", policy.AmbientLightSensor)
|
||||||
|
addDirective("autoplay", policy.Autoplay)
|
||||||
|
addDirective("battery", policy.Battery)
|
||||||
|
addDirective("camera", policy.Camera)
|
||||||
|
addDirective("cross-origin-isolated", policy.CrossOriginIsolated)
|
||||||
|
addDirective("display-capture", policy.DisplayCapture)
|
||||||
|
addDirective("document-domain", policy.DocumentDomain)
|
||||||
|
addDirective("encrypted-media", policy.EncryptedMedia)
|
||||||
|
addDirective("execution-while-not-rendered", policy.ExecutionWhileNotRendered)
|
||||||
|
addDirective("execution-while-out-of-viewport", policy.ExecutionWhileOutOfView)
|
||||||
|
addDirective("fullscreen", policy.Fullscreen)
|
||||||
|
addDirective("geolocation", policy.Geolocation)
|
||||||
|
addDirective("gyroscope", policy.Gyroscope)
|
||||||
|
addDirective("keyboard-map", policy.KeyboardMap)
|
||||||
|
addDirective("magnetometer", policy.Magnetometer)
|
||||||
|
addDirective("microphone", policy.Microphone)
|
||||||
|
addDirective("midi", policy.Midi)
|
||||||
|
addDirective("navigation-override", policy.NavigationOverride)
|
||||||
|
addDirective("payment", policy.Payment)
|
||||||
|
addDirective("picture-in-picture", policy.PictureInPicture)
|
||||||
|
addDirective("publickey-credentials-get", policy.PublicKeyCredentialsGet)
|
||||||
|
addDirective("screen-wake-lock", policy.ScreenWakeLock)
|
||||||
|
addDirective("sync-xhr", policy.SyncXHR)
|
||||||
|
addDirective("usb", policy.USB)
|
||||||
|
addDirective("web-share", policy.WebShare)
|
||||||
|
addDirective("xr-spatial-tracking", policy.XRSpatialTracking)
|
||||||
|
addDirective("clipboard-read", policy.ClipboardRead)
|
||||||
|
addDirective("clipboard-write", policy.ClipboardWrite)
|
||||||
|
addDirective("gamepad", policy.Gamepad)
|
||||||
|
addDirective("speaker-selection", policy.SpeakerSelection)
|
||||||
|
addDirective("conversion-measurement", policy.ConversionMeasurement)
|
||||||
|
addDirective("focus-without-user-activation", policy.FocusWithoutUserActivation)
|
||||||
|
addDirective("hid", policy.HID)
|
||||||
|
addDirective("idle-detection", policy.IdleDetection)
|
||||||
|
addDirective("interest-cohort", policy.InterestCohort)
|
||||||
|
addDirective("serial", policy.Serial)
|
||||||
|
addDirective("sync-script", policy.SyncScript)
|
||||||
|
addDirective("trust-token-redemption", policy.TrustTokenRedemption)
|
||||||
|
addDirective("unload", policy.Unload)
|
||||||
|
addDirective("window-placement", policy.WindowPlacement)
|
||||||
|
addDirective("vertical-scroll", policy.VerticalScroll)
|
||||||
|
|
||||||
|
// Join the directives and set the header
|
||||||
|
policyHeaderValue := strings.Join(policyHeader, ", ")
|
||||||
|
|
||||||
|
//Inject the new policy into the header
|
||||||
|
w.Header().Set("Permissions-Policy", policyHeaderValue)
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package permissionpolicy_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInjectPermissionPolicyHeader(t *testing.T) {
|
||||||
|
//Prepare the data for permission policy
|
||||||
|
testPermissionPolicy := permissionpolicy.GetDefaultPermissionPolicy()
|
||||||
|
testPermissionPolicy.Geolocation = []string{"self"}
|
||||||
|
testPermissionPolicy.Microphone = []string{"self", "https://example.com"}
|
||||||
|
testPermissionPolicy.Camera = []string{"*"}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
existingHeader string
|
||||||
|
policy *permissionpolicy.PermissionsPolicy
|
||||||
|
expectedHeader string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Default policy with a few limitations",
|
||||||
|
existingHeader: "",
|
||||||
|
policy: testPermissionPolicy,
|
||||||
|
expectedHeader: `accelerometer=*, ambient-light-sensor=*, autoplay=*, battery=*, camera=*, cross-origin-isolated=*, display-capture=*, document-domain=*, encrypted-media=*, execution-while-not-rendered=*, execution-while-out-of-viewport=*, fullscreen=*, geolocation=(self), gyroscope=*, keyboard-map=*, magnetometer=*, microphone=(self "https://example.com"), midi=*, navigation-override=*, payment=*, picture-in-picture=*, publickey-credentials-get=*, screen-wake-lock=*, sync-xhr=*, usb=*, web-share=*, xr-spatial-tracking=*, clipboard-read=*, clipboard-write=*, gamepad=*, speaker-selection=*, conversion-measurement=*, focus-without-user-activation=*, hid=*, idle-detection=*, interest-cohort=*, serial=*, sync-script=*, trust-token-redemption=*, unload=*, window-placement=*, vertical-scroll=*`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
if tt.existingHeader != "" {
|
||||||
|
rr.Header().Set("Permissions-Policy", tt.existingHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionpolicy.InjectPermissionPolicyHeader(rr, tt.policy)
|
||||||
|
|
||||||
|
gotHeader := rr.Header().Get("Permissions-Policy")
|
||||||
|
if !strings.Contains(gotHeader, tt.expectedHeader) {
|
||||||
|
t.Errorf("got header %s, want %s", gotHeader, tt.expectedHeader)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.2/semantic.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.2/semantic.min.js"></script>
|
||||||
<title>404 - Host Not Found</title>
|
<title>404 - Host Not Found</title>
|
||||||
<style>
|
<style>
|
||||||
h1, h2, h3, h4, h5, p, a, span{
|
h1, h2, h3, h4, h5, p, a, span, .ui.list .item{
|
||||||
font-family: 'Noto Sans TC', sans-serif;
|
font-family: 'Noto Sans TC', sans-serif;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
color: rgb(88, 88, 88)
|
color: rgb(88, 88, 88)
|
||||||
@ -22,9 +22,6 @@
|
|||||||
|
|
||||||
.diagram{
|
.diagram{
|
||||||
background-color: #ebebeb;
|
background-color: #ebebeb;
|
||||||
box-shadow:
|
|
||||||
inset 0px 11px 8px -10px #CCC,
|
|
||||||
inset 0px -11px 8px -10px #CCC;
|
|
||||||
padding-bottom: 2em;
|
padding-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,28 @@
|
|||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
var uptime5xxErrorMessage = {
|
||||||
|
"500": "Internal Server Error",
|
||||||
|
"501": "Not Implemented",
|
||||||
|
"502": "Bad Gateway",
|
||||||
|
"503": "Service Unavailable",
|
||||||
|
"504": "Gateway Timeout",
|
||||||
|
"505": "HTTP Version Not Supported",
|
||||||
|
"506": "Variant Also Negotiates",
|
||||||
|
"507": "Insufficient Storage",
|
||||||
|
"508": "Loop Detected",
|
||||||
|
"510": "Not Extended",
|
||||||
|
"511": "Network Authentication Required",
|
||||||
|
"520": "Web Server Returned an Unknown Error (Cloudflare)",
|
||||||
|
"521": "Web Server is Down (Cloudflare)",
|
||||||
|
"522": "Connection Timed Out (Cloudflare)",
|
||||||
|
"523": "Origin is Unreachable (Cloudflare)",
|
||||||
|
"524": "A Timeout Occurred (Cloudflare)",
|
||||||
|
"525": "SSL Handshake Failed (Cloudflare)",
|
||||||
|
"526": "Invalid SSL Certificate (Cloudflare)",
|
||||||
|
"527": "Railgun Error (Cloudflare)",
|
||||||
|
"530": "Site is Frozen (Pantheon)"
|
||||||
|
}
|
||||||
|
|
||||||
$('#utmEnable').checkbox({
|
$('#utmEnable').checkbox({
|
||||||
onChange: function() {
|
onChange: function() {
|
||||||
@ -78,6 +100,14 @@
|
|||||||
return(date.toLocaleString());
|
return(date.toLocaleString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveUptime5xxErrorMessage(errorCode){
|
||||||
|
if (uptime5xxErrorMessage[errorCode] != undefined){
|
||||||
|
return uptime5xxErrorMessage[errorCode]
|
||||||
|
}else{
|
||||||
|
return "Unknown Error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function renderUptimeData(key, value){
|
function renderUptimeData(key, value){
|
||||||
if (value.length == 0){
|
if (value.length == 0){
|
||||||
@ -101,26 +131,33 @@
|
|||||||
//Render status to html
|
//Render status to html
|
||||||
let thisStatus = value[i];
|
let thisStatus = value[i];
|
||||||
let dotType = "";
|
let dotType = "";
|
||||||
if (thisStatus.Online){
|
let statusCode = thisStatus.StatusCode;
|
||||||
if (thisStatus.StatusCode < 200 || thisStatus.StatusCode >= 300){
|
|
||||||
dotType = "error";
|
|
||||||
}else{
|
|
||||||
dotType = "online";
|
|
||||||
}
|
|
||||||
ontimeRate++;
|
|
||||||
}else{
|
|
||||||
if (thisStatus.StatusCode >= 500 && thisStatus.StatusCode < 600){
|
|
||||||
//Special type of error, cause by downstream reverse proxy
|
|
||||||
dotType = "error";
|
|
||||||
}else if (thisStatus.StatusCode == 401){
|
|
||||||
//Unauthorized error
|
|
||||||
dotType = "error";
|
|
||||||
}else{
|
|
||||||
dotType = "offline";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!thisStatus.Online && statusCode == 0){
|
||||||
|
dotType = "offline";
|
||||||
|
}else if (statusCode < 200){
|
||||||
|
//1xx
|
||||||
|
dotType = "error";
|
||||||
|
ontimeRate++;
|
||||||
|
}else if (statusCode < 300){
|
||||||
|
//2xx
|
||||||
|
dotType = "online";
|
||||||
|
ontimeRate++;
|
||||||
|
}else if (statusCode < 400){
|
||||||
|
//3xx
|
||||||
|
dotType = "online";
|
||||||
|
ontimeRate++;
|
||||||
|
}else if (statusCode < 500){
|
||||||
|
//4xx
|
||||||
|
dotType = "error";
|
||||||
|
ontimeRate++;
|
||||||
|
}else if (statusCode < 600){
|
||||||
|
//5xx
|
||||||
|
dotType = "error";
|
||||||
|
}else {
|
||||||
|
dotType = "offline";
|
||||||
|
}
|
||||||
|
|
||||||
let datetime = format_time(thisStatus.Timestamp);
|
let datetime = format_time(thisStatus.Timestamp);
|
||||||
statusDotList += `<div title="${datetime}" class="${dotType} statusDot"></div>`
|
statusDotList += `<div title="${datetime}" class="${dotType} statusDot"></div>`
|
||||||
}
|
}
|
||||||
@ -141,11 +178,13 @@
|
|||||||
onlineStatusCss = `color: #3bd671;`;
|
onlineStatusCss = `color: #3bd671;`;
|
||||||
}else{
|
}else{
|
||||||
if (value[value.length - 1].StatusCode >= 500 && value[value.length - 1].StatusCode < 600){
|
if (value[value.length - 1].StatusCode >= 500 && value[value.length - 1].StatusCode < 600){
|
||||||
currentOnlineStatus = `<i class="exclamation circle icon"></i> Misconfigured`;
|
var latestStatusCode = value[value.length - 1].StatusCode
|
||||||
|
currentOnlineStatus = `<i class="exclamation circle icon"></i>${latestStatusCode} - ${resolveUptime5xxErrorMessage(latestStatusCode)}`;
|
||||||
onlineStatusCss = `color: #f38020;`;
|
onlineStatusCss = `color: #f38020;`;
|
||||||
reminderEle = `<small style="${onlineStatusCss}">Downstream proxy server is online with misconfigured settings</small>`;
|
reminderEle = `<small style="${onlineStatusCss}">Downstream proxy server is responsive but returning server error</small>`;
|
||||||
}else if (value[value.length - 1].StatusCode >= 400 && value[value.length - 1].StatusCode <= 405){
|
}else if (value[value.length - 1].StatusCode >= 400 && value[value.length - 1].StatusCode <= 405){
|
||||||
switch(value[value.length - 1].StatusCode){
|
let latestStatusCode = value[value.length - 1].StatusCode;
|
||||||
|
switch(latestStatusCode){
|
||||||
case 400:
|
case 400:
|
||||||
currentOnlineStatus = `<i class="exclamation circle icon"></i> Bad Request`;
|
currentOnlineStatus = `<i class="exclamation circle icon"></i> Bad Request`;
|
||||||
break;
|
break;
|
||||||
@ -161,6 +200,9 @@
|
|||||||
case 405:
|
case 405:
|
||||||
currentOnlineStatus = `<i class="exclamation circle icon"></i> Method Not Allowed`;
|
currentOnlineStatus = `<i class="exclamation circle icon"></i> Method Not Allowed`;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
currentOnlineStatus = `<i class="exclamation circle icon"></i> Status Code: ${latestStatusCode}`;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
onlineStatusCss = `color: #f38020;`;
|
onlineStatusCss = `color: #f38020;`;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.2/semantic.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.2/semantic.min.js"></script>
|
||||||
<title>521 - Web server is down</title>
|
<title>521 - Web server is down</title>
|
||||||
<style>
|
<style>
|
||||||
h1, h2, h3, h4, h5, p, a, span{
|
h1, h2, h3, h4, h5, p, a, span, .ui.list .item{
|
||||||
font-family: 'Noto Sans TC', sans-serif;
|
font-family: 'Noto Sans TC', sans-serif;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
color: rgb(88, 88, 88)
|
color: rgb(88, 88, 88)
|
||||||
@ -22,9 +22,6 @@
|
|||||||
|
|
||||||
.diagram{
|
.diagram{
|
||||||
background-color: #ebebeb;
|
background-color: #ebebeb;
|
||||||
box-shadow:
|
|
||||||
inset 0px 11px 8px -10px #CCC,
|
|
||||||
inset 0px -11px 8px -10px #CCC;
|
|
||||||
padding-bottom: 2em;
|
padding-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user