forked from webhintio/webhintio.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
web.config
300 lines (287 loc) Β· 17.6 KB
/
web.config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
<?xml version="1.0" encoding="utf-8"?>
<!--
This configuration file is required if iisnode is used to run node processes behind
IIS or IIS Express. For more information, visit:
https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
-->
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<!-- Remove unnecesary headers -->
<remove name="X-Powered-By"/>
<!-- <remove name="server"/> -->
<!-- Security headers -->
<add name="Strict-Transport-Security" value="max-age=31536000"/>\
<add name="X-Content-Type-Options" value="nosniff"/>
</customHeaders>
</httpProtocol>
<!-- Visit http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx for more information on WebSocket support -->
<webSocket enabled="false"/>
<handlers>
<!-- Indicates that the app.js file is a node.js site to be handled by the iisnode module -->
<add name="iisnode" path="src/server/index.js" verb="*" modules="iisnode"/>
</handlers>
<!--
We still have some dynamic parts on the site that we want to compress. E.g.:
* JSON responses from the server
* dynamically generated html
* html pages served via `/` and not ending on `.html` (haven't figured out a way to do this mixed with our dynamic part)
-->
<urlCompression doStaticCompression="true" doDynamicCompression="true" dynamicCompressionBeforeCache="false" />
<staticContent>
<!-- We set the mimeType for all the types we are going to use in the site. IIS supports a few of those but
they not always have the right values so we are explicit.
Also we set `cache-control: no-cache` by default. We will override this based on the file's path
See https://docs.microsoft.com/en-us/iis/configuration/system.webserver/staticcontent/clientcache for more info -->
<clientCache cacheControlMode="DisableCache" />
<!-- The brotli mime type is unknown to IIS, we need it or otherwise files will not be served correctly -->
<remove fileExtension=".br" />
<mimeMap fileExtension=".br" mimeType="application/brotli" />
<!-- IIS doesn't set the right charset for text types -->
<remove fileExtension=".css"/>
<mimeMap fileExtension=".css" mimeType="text/css; charset=utf-8"/>
<remove fileExtension=".html" />
<mimeMap fileExtension=".html" mimeType="text/html; charset=utf-8" />
<remove fileExtension=".js"/>
<mimeMap fileExtension=".js" mimeType="text/javascript; charset=utf-8"/>
<remove fileExtension=".json"/>
<mimeMap fileExtension=".json" mimeType="application/json; charset=utf-8"/>
<remove fileExtension=".svg"/>
<mimeMap fileExtension=".svg" mimeType="image/svg+xml; charset=utf-8"/>
<remove fileExtension=".txt" />
<mimeMap fileExtension=".txt" mimeType="text/plain; charset=utf-8" />
<remove fileExtension=".xml"/>
<mimeMap fileExtension=".xml" mimeType="text/xml; charset=utf-8"/>
<remove fileExtension=".webmanifest"/>
<mimeMap fileExtension="webmanifest" mimeType="application/manifest+json; charset=utf-8"/>
<!-- font types -->
<remove fileExtension=".woff"/>
<mimeMap fileExtension=".woff" mimeType="font/woff"/>
<remove fileExtension=".woff2"/>
<mimeMap fileExtension=".woff2" mimeType="font/woff2"/>
</staticContent>
<rewrite>
<rewriteMaps>
<!-- pre-compressed files will be suffixed with br or gz -->
<!-- map of correct mime types to be restored -->
<rewriteMap name="CompressedExtensions" defaultValue="">
<add key="css.gz" value="text/css; charset=utf-8" />
<add key="html.gz" value="text/html; charset=utf-8" />
<add key="ico.gz" value="image/x-icon" />
<add key="js.gz" value="text/javascript; charset=utf-8" />
<add key="map.gz" value="application/json; charset=utf-8" />
<add key="svg.gz" value="image/svg+xml; charset=utf-8" />
<add key="txt.gz" value="text/plain; charset=utf-8" />
<add key="xml.gz" value="text/xml; charset=utf-8" />
<add key="webmanifest.gz" value="application/manifest+json; charset=utf-8" />
<add key="css.br" value="text/css; charset=utf-8" />
<add key="html.br" value="text/html; charset=utf-8" />
<add key="ico.br" value="image/x-icon" />
<add key="js.br" value="text/javascript; charset=utf-8" />
<add key="map.br" value="application/json; charset=utf-8" />
<add key="svg.br" value="image/svg+xml; charset=utf-8" />
<add key="txt.br" value="text/plain; charset=utf-8" />
<add key="xml.br" value="text/xml; charset=utf-8" />
<add key="webmanifest.br" value="application/manifest+json; charset=utf-8" />
</rewriteMap>
</rewriteMaps>
<outboundRules>
<!-- Clean service worker from old site -->
<rule name="sonarwhal" enabled="true">
<match serverVariable="RESPONSE_Clear_Site_Data" pattern="\.html" />
<action type="Rewrite" value=""storage"" />
</rule>
<!-- Restore the mime type for compressed assets. See below for more explanation -->
<rule name="RestoreMime" enabled="true">
<match serverVariable="RESPONSE_Content_Type" pattern=".*" />
<conditions>
<add input="{HTTP_URL}" pattern="\.((?:css|html|ico|js|map|svg|txt|xml|webmanifest)\.(gz|br))" />
<add input="{CompressedExtensions:{C:1}}" pattern="(.+)" />
</conditions>
<action type="Rewrite" value="{C:3}" />
</rule>
<!-- add vary header -->
<rule name="AddVaryAcceptEncoding" enabled="true">
<match serverVariable="RESPONSE_Vary" pattern=".*" />
<action type="Rewrite" value="Accept-Encoding" />
</rule>
<!-- indicate response is encoded with brotli -->
<rule name="AddEncodingBrotli" preCondition="PreCompressedBrotli" enabled="true" stopProcessing="true">
<match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
<action type="Rewrite" value="br" />
</rule>
<!-- indicate response is encoded with gzip -->
<rule name="AddEncodingZopfli" preCondition="PreCompressedZopfli" enabled="true" stopProcessing="true">
<match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
<action type="Rewrite" value="gzip" />
</rule>
<preConditions>
<preCondition name="PreCompressedZopfli">
<add input="{HTTP_URL}" pattern="\.((?:css|html|ico|js|map|svg|txt|xml|webmanifest)\.gz)" />
</preCondition>
<preCondition name="PreCompressedBrotli">
<add input="{HTTP_URL}" pattern="\.((?:css|html|ico|js|map|svg|txt|xml|webmanifest)\.br)" />
</preCondition>
</preConditions>
</outboundRules>
<rules>
<rule name="Redirect to https" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true"/>
<!-- WARMUP_REQUEST is needed to make sure the site starts asap on a deployment -->
<add input="{WARMUP_REQUEST}" pattern="1" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent"
appendQueryString="true"/>
</rule>
<!-- Redirects www.sonarwhal.com and www.webhint.io to webhint.io -->
<rule name="Redirect to non www" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{HTTP_HOST}" pattern="^www" />
</conditions>
<action type="Redirect" url="https://webhint.io{REQUEST_URI}" redirectType="Permanent"
appendQueryString="true"/>
</rule>
<!-- Redirects sonarwhal.com to webhint.io. Can't just use "sonarwhal" because of staging environment -->
<rule name="Redirect sonarwhal to webhint.io" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{HTTP_HOST}" pattern="^sonarwhal.com" />
</conditions>
<action type="Redirect" url="https://webhint.io{REQUEST_URI}" redirectType="Permanent"
appendQueryString="true"/>
</rule>
<rule name="Redirect to JSF CoC" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{REQUEST_URI}" pattern="/about/code_of_conduct/" />
</conditions>
<action type="Redirect" url="https://js.foundation/community/code-of-conduct" redirectType="Permanent"
appendQueryString="true"/>
</rule>
<!-- Needed for Let's encrypt -->
<rule name="wellknown" stopProcessing="true">
<match url="^\.well-known.*" />
<action type="Rewrite" url="{REQUEST_URI}"/>
</rule>
<!-- Redirect old rules pages to hints -->
<rule name="Redirect rules to hints" stopProcessing="false">
<match url="^docs\/user-guide\/rules\/rule-(.*)$" ignoreCase="true"/>
<action type="Redirect" redirectType="Permanent" url="/docs/user-guide/hints/hint-{R:1}" />
</rule>
<rule name="Redirect rules mainpage to hints" stopProcessing="false">
<match url="^docs\/user-guide\/rules\/$" ignoreCase="true"/>
<action type="Redirect" redirectType="Permanent" url="/docs/user-guide/hints/" />
</rule>
<!--
Compression rules. This works in combination with the `outbound rules` bellow. Basically what happens is:
1. We check if the user agent supprots compression via the `Accept-Encoding` header.
2. We prioritize `brotli` of `gzip`, and append the right extension (`.gz` or `.br`) and prepend `dist`.
`dist` is where all the pulic assets live. This is transparent to the user.
We assume all assets with those extensions have a `.gz` and `.br` version because of the build system we
have.
IIS then serves the asset applying the outbound rules.
3. If the final part of the file (`.ext.gz` or `.ext.br`) matches one of the `CompressedExtensions` `rewriteMap`, we
rewrite the `content-type` header
4. Based on the extension (`.gz` or `.br`), we rewrite the `content-encoding` header
-->
<rule name="ServerPreCompressedBrotli" stopProcessing="true">
<match url="^(.*/)?(.*?)\.(css|html|ico|js|map|svg|txt|xml|webmanifest)([?#].*)?$" ignoreCase="true"/>
<conditions>
<add input="{HTTP_ACCEPT_ENCODING}" pattern="br" negate="false" />
</conditions>
<action type="Rewrite" url="dist{REQUEST_URI}.br"/>
</rule>
<rule name="ServerPreCompressedZopfli" stopProcessing="true">
<match url="^(.*/)?(.*?)\.(css|html|ico|js|map|svg|txt|xml|webmanifest)([?#].*)?$" ignoreCase="true"/>
<conditions>
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" negate="false"/>
</conditions>
<action type="Rewrite" url="dist{REQUEST_URI}.gz"/>
</rule>
<!-- We want to respond only to /scanner/, /search/ and /about/changelog to have better stats -->
<rule name="ScannerSearchAndChangelogTrailing" stopProcessing="true">
<match url="(scanner|search|about\/changelog)$" ignoreCase="true"/>
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/"/>
</rule>
<!-- If the user agent reaches a /scanner, /search or /about/changelog page, it should be handled by our node server -->
<rule name="ScannerSearchAndChangelog" stopProcessing="true">
<match url="(?:scanner|search|about\/changelog)(.*)$" ignoreCase="true"/>
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="src/server/index.js"/>
</rule>
<!-- We want to add a trailing slash to the urls that do not have it and are not files (i.e. contain a ".") so we don't end up in a 404 page -->
<rule name="Add trailing slash" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{REQUEST_URI}" pattern="(\..*$|.*\/$|\?)" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>
<!--
We don't link to any `.html` page so we assume that all pages ending on `/` are going to point to a `index.html` file
The ^$ is for the homepage. Also, we add this at the end so /scanner/ and /search/ are served correctly via node
-->
<rule name="ServeCompressedHTMLBrotli" stopProcessing="true">
<match url="(^(.*\/)$|^$)" />
<conditions>
<add input="{HTTP_ACCEPT_ENCODING}" pattern="br" negate="false" />
</conditions>
<action type="Rewrite" url="dist{REQUEST_URI}index.html.br"/>
</rule>
<rule name="ServeCompressedHTMLZopfli" stopProcessing="true">
<match url="(^(.*\/)$|^$)" />
<conditions>
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" negate="false" />
</conditions>
<action type="Rewrite" url="dist{REQUEST_URI}index.html.gz"/>
</rule>
<!-- Fallback in case the user agent doesn't support compression -->
<rule name="static">
<match url="(?!scanner|search|about\/changelog).*$" ignoreCase="true"/>
<action type="Rewrite" url="dist{REQUEST_URI}"/>
</rule>
</rules>
</rewrite>
<!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
<security>
<requestFiltering removeServerHeader="true">
<hiddenSegments>
<remove segment="src"/>
</hiddenSegments>
<requestLimits maxQueryString="4096"/>
</requestFiltering>
</security>
<!-- Custom 404 page with Nellie lost in space. Needs to be used in combination with `system.web/customErrors` bellow -->
<httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
<remove statusCode="404" subStatusCode="-1"/>
<error statusCode="404" path="/dist/404/index.asp" responseMode="ExecuteURL"/>
</httpErrors>
<iisnode watchedFiles="web.config;*.js" debuggingEnabled="false"/>
<!--
You can control how Node is hosted within IIS using the following options:
* watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
* node_env: will be propagated to node as NODE_ENV environment variable
* debuggingEnabled - controls whether the built-in debugger is enabled
See https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config for a full list of options
-->
<!-- <iisnode watchedFiles="web.config;*.js"/> -->
</system.webServer>
<!-- All our static assets should be under `dist/static`, we set a long cache and the `immutable` directive, overriding
the `no-cache` we set up earlier -->
<location path="dist/static">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" cacheControlCustom="immutable" />
</staticContent>
</system.webServer>
</location>
</configuration>