mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-22 22:58:25 +00:00
commit
c67c861dc6
16
cmd/strelaypoolsrv/auto/gui.go
Normal file
16
cmd/strelaypoolsrv/auto/gui.go
Normal file
@ -0,0 +1,16 @@
|
||||
package auto
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
const (
|
||||
AssetsBuildDate = "Fri, 23 Oct 2015 23:02:30 GMT"
|
||||
)
|
||||
|
||||
func Assets() map[string][]byte {
|
||||
var assets = make(map[string][]byte, 1)
|
||||
|
||||
assets["index.html"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/6Q6e3PbNvL/51MgbKakfpVIyanbjizpN47zuMw1rafJTXvn891AJCTBpgiGBC27ib777YIgCVBUJKd5SORiX9hd7C4ATZ6+/PXiwz8vX5GVXMezJ08m+E1imiynDksckiwHNE2nTv6QhHLFk6UChSKRmYhjlk2djMX04SWV9KIGOrMnhExWjEb4AI9rJikJVzTLmZw6hVwMfnLMoZWU6YB9LPjd1Plj8I/zwYVYp1TyecwcgsJYAnRvX01ZtGQWZULXbOrccbZJRSYN5A2P5GoasTsesoF66ROecMlpPMhDGrPpyB92sIpYHmY8lVwkBrcORFrIlchsnBJJchmz2W9oF5JLKvNJUILK4Zgnt2SVscXUCYI1vQ+jxJ8LIXOZ0RRfQrEOakDw3H/unwZhnjcwf80BK88dAsYH38iHmOUrxmStggKV8gj5Zk1T8km/ELJifLmSY/LDcJjen2nwVn/76N1Y0FuDIOJ5CnMZk0QkzCaYBLWkSVA6HB/nInogYUzzfOpUDCsTRvyuGkLTUZ7ogFGjq5E23KUQMcGwAr4n9TASA0MOtnsKps0ki5yKm2T3chCCKwx+QMLXS5JnIRobjHuT+6BNES1imjFlaXpD74OYz/NgSTF4+WLBw+DEH/ojZXXQPWKZv+QLJzDYprPLmNGckQ3lkmxWPIZHRpZUrlhGIqV4auKj3hlLGZW4smT2AOFI0kwsM4ae3LHWp09EofkYbmS79X0f/JrSpDJAORqBT5zZS/h8Cs6A4ZkhdxKAwUzjGQppU+YrscEQsm0JAyseMcOOasrGGyEXRZaBDvEDAVVVFsj9mCVLuQJtNYCIBMKdEQ9QpJA0zv2leEfvLzMR5ogWCpg+WkKN9nxTXpB+Sfx7QRY0Iw3j+YNkOTC+5ywin4l6RRFpCfL3K68ZJMX6PJT8jr0Hj8D6V9RUQUiuQX2y4TBBiwgSX8JCWVGEMQfO1dQfMaPzO5bRJSMZlaVNwBfSwlD+n42G+djQ4Hae5gAarU/Xo9P18+H6h+H6anhN/o+MhiffG5YIch0hXTzXB1mOHsny9DDLk8dqeQTP54/kCWQHeX7/WD1XB1meHsnSziLB7hrm0dSBBO/MykEyeToYkAuauJLgEiaQjwiM94nAzLThkLIgYS0yRm8hRgtJBoN2mjqQEz4Ax5BnIWS8nP8J8cpSWMQq5oGQrItwpaeEslUiIFC2knzBMliaCFBrSopSJ50ruvOWfqzqmqrNdT4XEfNvPhYM8iCm8vJxcOKP/O9VjbzJ0Swl0ayTw5crArRBBYCBT4Asf6wBRzE/trbftEv7EZxTTKRiCSUo5bniirAA3oI29STAclwW5gZaz0RERcw8t27w3D65gvHrHnz4Cx5DOfVc5U4YWRSJSnReT/cHGZNFljRwhdiHnMtCjgmzV/cRfEE8nv9Cf/FS7ANfQ5WTJXqvRz5/Jk95/hobNFYDNW934J4ZPORDysSikUCm0ylxiyRiC0i3kdszh8jo7ImmvYNiUQD/HKBX9YTc2xf4+U59vlGfH9Tn5Qv3um+sQ8jzcwjVKXkHFd5fxEJknnqMxVJrTAJSQ3Bl93qW8DsaFwwYlNgVcio2gDwc9k3GpbAeMmgm3hhIcer1jBat4j08q0GmFYbtNs/mV4kzGFaW0oaq6QmLIYHs4qnvq5LRdVuadqRS0pfiNb9nkWeEyHfEhb/flUxKYiTdqhBs9hqe27HXwHB1n+WhSBm67VkGK+l9/YYbC/XwUX3COkmhUTMDuSTtk4YQnpEMvj7Cf01S2aZE93VuhIkvIMPrpliPLZngKYx82p61SGSR78KLjO8Cq74QY/XaGilrClJo45ptz5gMq5ht2iwD2FWJxuQKgs/6Vwf+Tkdk8LIbH3vgkiURpBJN9Xf20B5X6jbArV4olVfUTu1S28DDBriJzZaF/LTIV94nxBmrnVmfYEs8Lh2z7VXhZPOvqLFvbvGvEuNCZK9ouPJa8ozQqUDmuimXVq2c6t0hP9kiqgWqkVBfcKjMCnZmYFSrpzUHTCWQ68/qF8nWsD2TyOKZ537Dk4X4oEFuz8f9vFclIsuszmsmQ8z4uv46Wo6Kfohi6TkB+DEVPJFOz4dKnXj13IFDCm43JmWZtIu37T+9P5iSipOPeyYNrpFx5wrWYxtSVjtfVb53NPUiERZr6DlQ0Vcxw8cXD28jzwUMt9c3bP2nEBDkoyaZA8YHKCJvYbm0uJZg/7dfz1++O7807G+kcZjnGpooc2nuDZpyNkbIKICduKEqqQxQTyiE1kwyPSfPpW4jn5AgIH87/8Ns5iLBcmz2NiK7bdJyxn08YlD2BZGQZWLQBoIiZDqNjoMAcyI6Gx9bQmBpw25EEtVREWhN0JfYsM1vYMVbcmi2NNNalzkQLWc0C1e1EsF//v3/AciHEM3TmMNEv0W31ZZSgttLBq2lsEFe2fZp2qnbO7MwK8WuFAJsh66BpHweXTeoUGLq5yYfX9U2QyoAGLaxl9BvLBfxHdomFiFVqQXmTBwsZugCkUu19M8sh2eKir1h4i2Gd7PgKm9sNhtfshiaa9XaqYoSuG2m9pIkHWtyd10er7DBwixstm2sxWua1aCvFkyZqc25m1iGXd5XlfLZRx+6Oij8vb0OeMOkrNMM0TV2gedyez1g5Ddt7jYyvHpVAOm6fR5FGXapzvjkZPjj0MGmxQnKsXZyPM4TX6F5q5c4yhV7c1PZSBgrTrVnfXLLdpad0XZbxFeAe43lzS0bP7dNSLrwv2vpqqD26tVt5mG5ZTpyybffdmHwBAyVhEh/nmV0Z14HbKOY7BqIw1bjfpdV11yvFO6eKevBsxafbSuTbZ/sG7OWi6/fPEuQgb/t2L39xbj8el0O5oeSUU1iEEBSoHHsVVTtxsSc2k6zbrdYmHLmAnaOeUeP8TOVPyfLF2rYyj9fXep1+UJszG31fsN/BrI9VM3yLiJXW4k9CbiNnoqcy3LH1z0dT3Hw8fxFFhHEsn4XyVIBbJ+29i37cs/ZDkmltvreHS4jS3cmu8NlO9RZjS31ykY4u1W78t0WEQe8Vset7TOun/rWOFCO1VmZBVV3N+Omj+q3FmSr9zet1M4Spbq+Pjzb1fpCDXjt1ALtl7hlFyIW2Zi437x+PYQ/br8T69eUhlw+wNbK/6kb43d9/3PSHl7wOD4kBHEMEc9P2wjdNiSkvJjZZ3lIIDTiBewIPcuA9qE+HpgO8ZjFyrQWTg+QTkFxO4X27H1VK4j0DR4Gnd7te9Weqldq04MG0nK0diTutTrc+BbAv0N2FxvPkmxQQTssL0q5npbf65JAo+hnnsMwHn+sRZEzcacOPfbkclsIqJ546vC3hNp2OFZgIY+VF8YiZ95jpYQxD2+/JOLQsiJko6xdztfs6uokYvV2DfTYDq9PnP/OY5rcOgeqs/Falhaf3cM0I09PvAr/fcUQnOUvuNR1p2Rh4KIlrIJT3bhBMzSyzYKcIMj+Bbtfb/TclHdcfayPHdT39lp9NefKT5pDaWzRyuvXoFo3jrqWMI8ijOvf+pQ/nU3meM9p+We7nQTzmX3VqZOBUNfy+ZULxf+ORywazB/ca2dWvZL5A5kUyPGLBEpEMeu4LjWul7XjjauRDoWU5T7wNczuPT5CrcBjqEaBGoF8xjthNnbWDPLc2imnmc3aFz5dUqwc+BTPWvVZtzOrz/0akXuuQY+WtnsLaotsjgIbmV03p48RaN6g2tIuysvUljD7xvVoSTocYBGKGFyLPzGwOFvj/o3giYdHJL2vkHHlLmMxp/EAL3Mh5OxZGcv0ETxmZOjM3iiQuiMmMV9z2TGBNuGBG8bjNYAs061CkagHFnVdYILlGpM9xoQpywb64v2v2bGDkTKmDtdD1uwg/wsm7eBW2rVLm6807M4PP8xfzdh5Da9TQAy9ozym87j+wcKkfQVrZv9JUP5e7H8AAAD//wEAAP//xqcvZ0AmAAA=")
|
||||
return assets
|
||||
}
|
269
cmd/strelaypoolsrv/gui/index.html
Normal file
269
cmd/strelaypoolsrv/gui/index.html
Normal file
@ -0,0 +1,269 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" ng-app="syncthing" ng-controller="relayDataController">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>Relay stats</title>
|
||||
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
#map {
|
||||
height: 600px;
|
||||
}
|
||||
.ng-cloak {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="ng-cloak">
|
||||
<div class="container">
|
||||
<h1>Relay Pool Data</h2>
|
||||
<div ng-if="!started" class="text-center">
|
||||
<img src="//cdnjs.cloudflare.com/ajax/libs/galleriffic/2.0.1/css/loader.gif"/>
|
||||
<p>Please wait while we gather data</p>
|
||||
<p ng-repeat="entry in progress" class="ng-cloak">{{ entry.name }}... <span ng-if="entry.done">Done!</span></p>
|
||||
</div>
|
||||
<div>
|
||||
<div ng-show="started" class="ng-hide">
|
||||
<p>
|
||||
Currently {{ relays.length }} relays online ({{ totals.goMaxProcs }} cores in total).
|
||||
</p>
|
||||
<p>
|
||||
So far {{ totals.bytesProxied | bytes }} proxied.
|
||||
Currently {{ totals.numActiveSessions }} active sessions, with {{ totals.numConnections }} clients online.
|
||||
</p>
|
||||
<p>
|
||||
Average rates in last
|
||||
<span>10s: {{ totals.kbps10s1m5m15m30m60m[0] * 1024 | bytes }}/s</span>
|
||||
<span>1m: {{ totals.kbps10s1m5m15m30m60m[1] * 1024 | bytes }}/s</span>
|
||||
<span>5m: {{ totals.kbps10s1m5m15m30m60m[2] * 1024 | bytes }}/s</span>
|
||||
<span>15m: {{ totals.kbps10s1m5m15m30m60m[3] * 1024 | bytes }}/s</span>
|
||||
<span>30m: {{ totals.kbps10s1m5m15m30m60m[4] * 1024 | bytes }}/s</span>
|
||||
<span>1h: {{ totals.kbps10s1m5m15m30m60m[5] * 1024 | bytes }}/s</span>
|
||||
</p>
|
||||
</div>
|
||||
<div id="map"></div> <!-- Can't hide the map, otherwise it freaks out -->
|
||||
<p ng-show="started" class="ng-hide">The circle size represents how much bytes the relay transfered relative to other relays</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
|
||||
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
|
||||
<script src="//maps.googleapis.com/maps/api/js"></script>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
angular.module('syncthing', [
|
||||
])
|
||||
.filter('bytes', function() {
|
||||
return function(bytes, precision) {
|
||||
if (isNaN(parseFloat(bytes)) || !isFinite(bytes)) return '-';
|
||||
if (typeof precision === 'undefined') precision = 1;
|
||||
|
||||
var units = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'],
|
||||
number = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
|
||||
var value = (bytes / Math.pow(1000, Math.floor(number)));
|
||||
if (!isFinite(value)) {
|
||||
value = 0;
|
||||
precision = 0;
|
||||
}
|
||||
if (!isFinite(number)) {
|
||||
units = 'bytes';
|
||||
} else {
|
||||
units = units[number];
|
||||
}
|
||||
return value.toFixed(precision) + ' ' + units;
|
||||
}
|
||||
})
|
||||
.controller('relayDataController', ['$scope', '$rootScope', '$http', '$q', '$compile', function($scope, $rootScope, $http, $q, $compile) {
|
||||
$scope.started = false;
|
||||
$scope.geoip = {};
|
||||
$scope.status = {};
|
||||
$scope.uri = {};
|
||||
$scope.progress = [];
|
||||
$scope.totals = {
|
||||
bytesProxied: 0,
|
||||
goMaxProcs: 0,
|
||||
kbps10s1m5m15m30m60m: [0, 0, 0, 0, 0, 0],
|
||||
numActiveSessions: 0,
|
||||
numConnections: 0,
|
||||
numPendingSessionKeys: 0,
|
||||
numProxies: 0,
|
||||
};
|
||||
|
||||
function initProgress(name) {
|
||||
$scope.progress.push({name: name, done: false});
|
||||
}
|
||||
|
||||
function progressDone(name) {
|
||||
angular.forEach($scope.progress, function(progress) {
|
||||
if (progress.name == name) {
|
||||
progress.done = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var map;
|
||||
var template = $('#infoTemplate').html();
|
||||
|
||||
initProgress("Fetching relays");
|
||||
$http.get("/endpoint").then(function(response) {
|
||||
progressDone("Fetching relays");
|
||||
|
||||
$scope.relays = response.data.relays;
|
||||
|
||||
map = new google.maps.Map(document.getElementById('map'), {
|
||||
zoom: 1,
|
||||
mapTypeId: google.maps.MapTypeId.ROADMAP
|
||||
});
|
||||
|
||||
var promises = [];
|
||||
angular.forEach($scope.relays, function(relay) {
|
||||
var uri = document.createElement('a');
|
||||
|
||||
// HAX, otherwise doesn't work
|
||||
uri.href = relay.url.replace('relay://', 'http://');
|
||||
|
||||
// Convert query string to object
|
||||
uri.args = {};
|
||||
angular.forEach(uri.search.replace(/^\?/, '').split('&'), function(query) {
|
||||
var split = query.split('=');
|
||||
uri.args[split[0]] = split[1];
|
||||
})
|
||||
|
||||
$scope.uri[relay.url] = uri;
|
||||
|
||||
initProgress("Resolving location for " + uri.hostname);
|
||||
var resolveGeoIp = $http.get('http://www.telize.com/geoip/' + uri.hostname).then(function (response) {
|
||||
progressDone("Resolving location for " + uri.hostname);
|
||||
|
||||
$scope.geoip[relay.url] = response.data;
|
||||
});
|
||||
|
||||
promises.push(resolveGeoIp);
|
||||
|
||||
var resolveStatus = $q.defer();
|
||||
|
||||
initProgress("Getting relay status for" + uri.hostname);
|
||||
$http.get("http://" + uri.hostname + (uri.args.statusAddr || ":22070") + "/status").then(function (response) {
|
||||
progressDone("Getting relay status for" + uri.hostname);
|
||||
$scope.status[relay.url] = response.data;
|
||||
angular.forEach($scope.totals, function(value, key) {
|
||||
if (typeof $scope.totals[key] == 'number') {
|
||||
$scope.totals[key] += response.data[key];
|
||||
} else if (typeof $scope.totals[key] == 'object' && $scope.totals[key] instanceof Array) {
|
||||
angular.forEach($scope.totals[key], function(value, index) {
|
||||
$scope.totals[key][index] += response.data[key][index];
|
||||
});
|
||||
}
|
||||
});
|
||||
resolveStatus.resolve(response.data);
|
||||
}, function() {
|
||||
progressDone("Getting relay status for" + uri.hostname);
|
||||
|
||||
resolveStatus.resolve(response.data);
|
||||
});
|
||||
|
||||
promises.push(resolveStatus);
|
||||
});
|
||||
|
||||
$q.all(promises).then(function() {
|
||||
$scope.started = true;
|
||||
var bounds = new google.maps.LatLngBounds();
|
||||
|
||||
angular.forEach($scope.relays, function(relay) {
|
||||
var scope = $rootScope.$new(true);
|
||||
var geoip = $scope.geoip[relay.url];
|
||||
var position = new google.maps.LatLng(geoip.latitude, geoip.longitude);
|
||||
|
||||
scope.status = $scope.status[relay.url];
|
||||
scope.geoip = geoip;
|
||||
scope.relay = relay;
|
||||
scope.uri = $scope.uri[relay.url];
|
||||
|
||||
var marker = new google.maps.Marker({
|
||||
position: position,
|
||||
map: map,
|
||||
title: relay.url,
|
||||
});
|
||||
|
||||
if (scope.status) {
|
||||
marker.circle = new google.maps.Circle({
|
||||
strokeColor: '#FF0000',
|
||||
strokeOpacity: 0.8,
|
||||
strokeWeight: 2,
|
||||
fillColor: '#FF0000',
|
||||
fillOpacity: 0.35,
|
||||
map: map,
|
||||
center: position,
|
||||
radius: ((scope.status.bytesProxied * 100) / $scope.totals.bytesProxied) * 5000
|
||||
});
|
||||
}
|
||||
|
||||
var content = $compile(template)(scope)[0];
|
||||
|
||||
marker.info = new google.maps.InfoWindow();
|
||||
marker.info.setContent(content);
|
||||
|
||||
marker.addListener('mouseover', function() {
|
||||
marker.info.open(map, marker);
|
||||
});
|
||||
|
||||
marker.addListener('mouseout', function() {
|
||||
marker.info.close();
|
||||
});
|
||||
|
||||
marker.addListener('click', function() {
|
||||
if (scope.status) {
|
||||
window.open("http://" + scope.uri.hostname + (scope.uri.args.statusAddr || ":22070") + "/status", "_blank");
|
||||
}
|
||||
});
|
||||
|
||||
bounds.extend(marker.position);
|
||||
});
|
||||
|
||||
map.fitBounds(bounds);
|
||||
if ($scope.relays.length == 1) {
|
||||
map.setZoom(13);
|
||||
}
|
||||
$scope.started = true;
|
||||
});
|
||||
});
|
||||
}]);
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="infoTemplate">
|
||||
<div>
|
||||
<p><b>{{ uri.hostname }}</b> <span ng-if="status.options['provided-by']">provided by <u>{{ status.options['provided-by'] }}</u></span></p>
|
||||
<div ng-if="status">
|
||||
<span ng-if="status.startTime">Start time: {{ status.startTime | date:"medium" }}</br></span>
|
||||
<span ng-if="status.bytesProxied != undefined">Proxied: {{ status.bytesProxied | bytes }}</br></span>
|
||||
<span ng-if="status.numActiveSessions != undefined">Sessions: {{ status.numActiveSessions }}</br></span>
|
||||
<span ng-if="status.numConnections != undefined">Clients: {{ status.numConnections }}</br></span>
|
||||
<span ng-if="status.options.pools">Pools: {{ status.options.pools.join(', ') }}</br></span>
|
||||
<span ng-if="status.options['global-rate'] != undefined">
|
||||
<span ng-if="status.options['global-rate'] > 0">Global rate limit: {{ status.options['global-rate'] | bytes }}/s</span>
|
||||
<span ng-if="status.options['global-rate'] == 0">Global rate limit: unlimited</span>
|
||||
</br>
|
||||
</span>
|
||||
<span ng-if="status.options['per-session-rate'] != undefined">
|
||||
<span ng-if="status.options['per-session-rate'] > 0">Session rate limit: {{ status.options['per-session-rate'] | bytes }}/s</span>
|
||||
<span ng-if="status.options['per-session-rate'] == 0">Session rate limit: unlimited</span>
|
||||
</br>
|
||||
</span>
|
||||
</div>
|
||||
<div ng-if="!status">
|
||||
Data unavailable.
|
||||
<div>
|
||||
</div>
|
||||
</script>
|
||||
</html>
|
@ -1,8 +1,12 @@
|
||||
// Copyright (C) 2015 Audrius Butkevicius and Contributors (see the CONTRIBUTORS file).
|
||||
|
||||
//go:generate go run genassets.go gui auto/gui.go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
@ -10,6 +14,7 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -20,6 +25,7 @@ import (
|
||||
"github.com/golang/groupcache/lru"
|
||||
"github.com/juju/ratelimit"
|
||||
|
||||
"github.com/syncthing/relaypoolsrv/auto"
|
||||
"github.com/syncthing/syncthing/lib/relay/client"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
@ -149,6 +155,7 @@ func main() {
|
||||
}
|
||||
|
||||
handler := http.NewServeMux()
|
||||
handler.HandleFunc("/", handleAssets)
|
||||
handler.HandleFunc("/endpoint", handleRequest)
|
||||
|
||||
srv := http.Server{
|
||||
@ -162,6 +169,72 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func handleAssets(w http.ResponseWriter, r *http.Request) {
|
||||
assets := auto.Assets()
|
||||
path := r.URL.Path[1:]
|
||||
if path == "" {
|
||||
path = "index.html"
|
||||
}
|
||||
|
||||
bs, ok := assets[path]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if r.Header.Get("If-Modified-Since") == auto.AssetsBuildDate {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
|
||||
mtype := mimeTypeForFile(path)
|
||||
if len(mtype) != 0 {
|
||||
w.Header().Set("Content-Type", mtype)
|
||||
}
|
||||
|
||||
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
} else {
|
||||
// ungzip if browser not send gzip accepted header
|
||||
var gr *gzip.Reader
|
||||
gr, _ = gzip.NewReader(bytes.NewReader(bs))
|
||||
bs, _ = ioutil.ReadAll(gr)
|
||||
gr.Close()
|
||||
}
|
||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(bs)))
|
||||
w.Header().Set("Last-Modified", auto.AssetsBuildDate)
|
||||
w.Header().Set("Cache-Control", "public")
|
||||
|
||||
w.Write(bs)
|
||||
}
|
||||
|
||||
func mimeTypeForFile(file string) string {
|
||||
// We use a built in table of the common types since the system
|
||||
// TypeByExtension might be unreliable. But if we don't know, we delegate
|
||||
// to the system.
|
||||
ext := filepath.Ext(file)
|
||||
switch ext {
|
||||
case ".htm", ".html":
|
||||
return "text/html"
|
||||
case ".css":
|
||||
return "text/css"
|
||||
case ".js":
|
||||
return "application/javascript"
|
||||
case ".json":
|
||||
return "application/json"
|
||||
case ".png":
|
||||
return "image/png"
|
||||
case ".ttf":
|
||||
return "application/x-font-ttf"
|
||||
case ".woff":
|
||||
return "application/x-font-woff"
|
||||
case ".svg":
|
||||
return "image/svg+xml"
|
||||
default:
|
||||
return mime.TypeByExtension(ext)
|
||||
}
|
||||
}
|
||||
|
||||
func handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
switch r.Method {
|
||||
|
Loading…
x
Reference in New Issue
Block a user