Search Unity

SOLVED: IIS - configuring it to serve out the new WebGL stack files - how?

Discussion in 'Unity 5 Pre-order Beta' started by twobob, Dec 5, 2014.

  1. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    TL,DR;
    SOLUTION:

    On my host I had to disable Dynamic compression,

    In addition it (my browser?) seemed to be finicky about the charset
    (.jsgz wanted application/x-javascript; charset=UTF-8)

    I also had to register all 5 types in the mime section - not just the two in the original web.config or I got 404.3 errors

    For some reason I did not get gzip attached to my RESPONSE HEADERS so I mangled together the following, which attempts to do all these things.

    Code (csharp):
    1.  
    2. <?xml version="1.0" encoding="UTF-8"?>
    3. <configuration>
    4. <system.webServer>
    5.   <rewrite>
    6.   <rules>
    7.   <rule name="Imported Rule 1" enabled="true" stopProcessing="true">
    8.   <match url="(.*)Data(.*)\.js" ignoreCase="true" />
    9.   <conditions logicalGrouping="MatchAll">
    10.   <add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" ignoreCase="true" />
    11.   </conditions>
    12.   <action type="Rewrite" url="{R:1}Compressed{R:2}.jsgz" />
    13.   </rule>
    14.   <rule name="Imported Rule 2" enabled="true" stopProcessing="true">
    15.   <match url="(.*)Data(.*)\.data" ignoreCase="true" />
    16.   <action type="Rewrite" url="{R:1}Compressed{R:2}.datagz" />
    17.   <conditions>
    18.   </conditions>
    19.   </rule>
    20.   <rule name="Imported Rule 3" enabled="true" stopProcessing="true">
    21.   <match url="(.*)Data(.*)\.mem" ignoreCase="true" />
    22.   <action type="Rewrite" url="{R:1}Compressed{R:2}.memgz" />
    23.   <conditions>
    24.   </conditions>
    25.   </rule>
    26.   <rule name="Imported Rule 4" enabled="true" stopProcessing="true">
    27.   <match url="(.*)Data(.*)\.unity3d" ignoreCase="true" />
    28.   <action type="Rewrite" url="{R:1}Compressed{R:2}.unity3dgz" />
    29.   <conditions>
    30.   </conditions>
    31.   </rule>
    32.   </rules>
    33.         <outboundRules>
    34.   <!-- FIRST SETUP THE SWITCHES FOR THE RESPONSE ENCODING //-->
    35.   <rule name="Rewrite JSGZ header" preCondition="IsJSGZ" stopProcessing="false">
    36.   <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    37.   <action type="Rewrite" value="gzip" />
    38.   </rule>
    39.   <rule name="Rewrite MemGZ header" preCondition="IsMemGZ" stopProcessing="false">
    40.   <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    41.   <action type="Rewrite" value="gzip" />
    42.   </rule>
    43.   <rule name="Rewrite DataGZ header" preCondition="IsDataGZ" stopProcessing="false">
    44.   <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    45.   <action type="Rewrite" value="gzip" />
    46.   </rule>
    47.   <rule name="Rewrite Unity3DGZ header" preCondition="IsUnity3DGZ" stopProcessing="true">
    48.   <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    49.   <action type="Rewrite" value="gzip" />
    50.   </rule>
    51.   <!-- AND SETUP THE MATCHES FOR THE RESPONSE ENCODING SWITCHES //-->
    52.   <preConditions>
    53.   <preCondition name="IsJSGZ">
    54.   <add input="{PATH_INFO}" pattern="\.jsgz$" />
    55.   </preCondition>
    56.   <preCondition name="IsMemGZ">
    57.   <add input="{PATH_INFO}" pattern="\.memgz$" />
    58.   </preCondition>
    59.   <preCondition name="IsDataGZ">
    60.   <add input="{PATH_INFO}" pattern="\.datagz$" />
    61.   </preCondition>
    62.   <preCondition name="IsUnity3DGZ">
    63.   <add input="{PATH_INFO}" pattern="\.unity3dgz$" />
    64.   </preCondition>
    65.   </preConditions>
    66.   </outboundRules>
    67.   </rewrite>
    68.   <staticContent>
    69.   <mimeMap fileExtension=".mem" mimeType="application/octet-stream" />
    70.   <mimeMap fileExtension=".data" mimeType="application/octet-stream" />
    71.   <mimeMap fileExtension=".memgz" mimeType="application/octet-stream" />
    72.   <mimeMap fileExtension=".datagz" mimeType="application/octet-stream" />
    73.   <mimeMap fileExtension=".unity3dgz" mimeType="application/octet-stream" />
    74.   <mimeMap fileExtension=".jsgz" mimeType="application/x-javascript; charset=UTF-8" />
    75.   </staticContent>
    76.   <urlCompression doStaticCompression="true" doDynamicCompression="false" />
    77. </system.webServer>
    78. </configuration>
    79.  
    That one web.config needs dropping either in the root of the site you are hosting it on - or the main subfolder of the game you want to serve.

    Whether or not you will need some or all of this I do not know.

    I needed all of it.

    Hope it helps someone. Massive thanks to philwinkel for his tireless efforts of assistance.



    ----------------------------------------------------------------------------
    ORIG POST:
    So I pored over the docs (such as they were, the ones I could find); Watched every video I could find about deployment (none actually useful); Tried web-searching; Read several, almost, related threads about web.config (the first part I posted below), Nothing actually seems to cover what I am experiencing.

    I can not for the life of me figure out how to serve these files via IIS.
    I think I have tried every permutation I can think of now of configurations (which isn't admittedly many)

    I get that there are some new file types. and they need mime registering. (see below)

    I also observe that - through testing - unless I actually also allow the mime types of the .datagz .memgz .jsgz to be registered that they are not served. (I can find no reference to this requirement anywhere)

    Here is what I have so far:

    For some reason my latest build didn't even spit out a web.config (a previous one did) - it is just a red plane and a green cube. nothing fancy.

    In the web.config that was generated I have

    Code (csharp):
    1.  
    2. <?xml version="1.0" encoding="UTF-8"?>
    3. <configuration>
    4.     <system.webServer>
    5.         <staticContent>
    6.             <mimeMap fileExtension=".mem" mimeType="application/octet-stream" />
    7.             <mimeMap fileExtension=".data" mimeType="application/octet-stream" />
    8.         </staticContent>
    9.     </system.webServer>
    10. </configuration>
    11.  
    and the .htaccess file (which is not IIS friendly directly but can be imported) says

    Code (csharp):
    1.  
    2. Options +FollowSymLinks
    3. RewriteEngine on
    4.  
    5. RewriteCond %{HTTP:Accept-encoding} gzip
    6. RewriteRule (.*)Data(.*)\.js $1Compressed$2\.jsgz [L]
    7. RewriteRule (.*)Data(.*)\.data $1Compressed$2\.datagz [L]
    8. RewriteRule (.*)Data(.*)\.mem $1Compressed$2\.memgz [L]
    9. RewriteRule (.*)Data(.*)\.unity3d $1Compressed$2\.unity3dgz [L]
    10. AddEncoding gzip .jsgz
    11. AddEncoding gzip .datagz
    12. AddEncoding gzip .memgz
    13. AddEncoding gzip .unity3dgz
    14.  

    which as far as I can tell is the same as 4 rewrite rules in IIS

    URLrewrite.JPG

    (careful - when you import the rules directly via the IIS importer: the format will be wrong and it will be appending an extra / after the rewritten URL and before the filename - like /Compressed/fileuploader/.jsgz - so fix that by eliding the extra / from the rule.

    You can jump on the actual server and run the requests locally to check the errors if you have it configured this way.

    Here is a previous request for: http://kaycare.co.uk/games/WebGL/Data/fileloader.js
    (requested directly)

    I got the error:

    HTTP Error 404.3 - Not Found
    The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.

    Module StaticFileModule
    Notification ExecuteRequestHandler
    Handler StaticFile
    Error Code 0x80070032
    Requested URL /games/WebGL/Compressed/fileloader.jsgz
    Physical Path \games\WebGL\Compressed\fileloader.jsgz
    Logon Method Anonymous
    Logon User Anonymous


    SO TO FIX THIS I MADE THE FILE BELOW

    In addition it seems like then (as I was saying before) I have to also allow the various compressed types to be served?

    I made this:

    Which is a rewrite of http://forums.iis.net/post/1970627.aspx

    Code (csharp):
    1.  
    2. <?xml version="1.0" encoding="UTF-8"?>
    3. <configuration>
    4. <system.webServer>
    5.      <rewrite>
    6.          <outboundRules>
    7.         <!-- FIRST SETUP THE SWITCHES FOR THE RESPONSE ENCODING //-->
    8.              <rule name="Rewrite JSGZ header" preCondition="IsJSGZ" stopProcessing="false">
    9.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    10.                  <action type="Rewrite" value="gzip" />
    11.              </rule>
    12.             <rule name="Rewrite MemGZ header" preCondition="IsMemGZ" stopProcessing="false">
    13.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    14.                  <action type="Rewrite" value="gzip" />
    15.              </rule>
    16.               <rule name="Rewrite DataGZ header" preCondition="IsDataGZ" stopProcessing="false">
    17.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    18.                  <action type="Rewrite" value="gzip" />
    19.              </rule>
    20.             <rule name="Rewrite Unity3DGZ header" preCondition="IsUnity3DGZ" stopProcessing="true">
    21.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    22.                  <action type="Rewrite" value="gzip" />
    23.              </rule>
    24.              <!-- AND SETUP THE MATCHES FOR THE RESPONSE ENCODING SWITCHES //-->
    25.             <preConditions>
    26.                  <preCondition name="IsJSGZ">
    27.                      <add input="{PATH_INFO}" pattern="\.jsgz$" />
    28.             </preCondition>
    29.                  <preCondition name="IsMemGZ">
    30.                      <add input="{PATH_INFO}" pattern="\.memgz$" />
    31.                  </preCondition>
    32.             <preCondition name="IsDataGZ">
    33.                      <add input="{PATH_INFO}" pattern="\.datagz$" />
    34.                  </preCondition>
    35.             <preCondition name="IsUnity3DGZ">
    36.                      <add input="{PATH_INFO}" pattern="\.unity3dgz$" />
    37.                  </preCondition>
    38.              </preConditions>
    39.         </outboundRules>
    40.      </rewrite>
    41.      <staticContent>
    42.     <!-- AND MIME REGISTER THE TYPES //-->
    43.          <mimeMap fileExtension=".jsgz" mimeType="application/x-javascript" />
    44.         <mimeMap fileExtension=".datagz" mimeType="application/octet-stream" />
    45.         <mimeMap fileExtension=".memgz" mimeType="application/octet-stream" />
    46.         <mimeMap fileExtension=".unity3dgz" mimeType="application/octet-stream" />    
    47.         <mimeMap fileExtension=".mem" mimeType="application/octet-stream" />
    48.         <mimeMap fileExtension=".data" mimeType="application/octet-stream" />
    49.      </staticContent>
    50. </system.webServer>
    51. </configuration>
    52.  
    53.  
    To handle that bit. not sure I got it right?

    However when I finally put all this in place I end up with an Illegal character complaint?

    (because the zipped file is NOT a script one would assume) - so it's now "serving" but not being "serviced"

    Anyone who has any knowledge I would be very appreciative.

    I did try out the "Answers" section for a day first, but this was drowned out in "How do I script" noise.

    I see that this answer will have great value for all MS IIS7 users in the future and as such hope you will forgive a little cross-posting. I waited a decent time.

    Kind regards,

    Much confused.
     
    Last edited: Dec 6, 2014
    Jodon and Caio_Lib like this.
  2. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    So what's happening exactly? In your browser's network tab, look at the requests for those files - what kind of response is the web server sending?

    If it's a 404.3 error - mime type missing, then you just need to add the mime types to your application root web.config:

    <configuration>
    <system.webServer>
    <staticContent>
    <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
    <mimeMap fileExtension=".m4v" mimeType="video/m4v" />
    </staticContent>
    </system.webServer>
    </configuration>

    I see you already did that for the .mem and .data mime types, but perhaps you should add all the unique file extensions that a unity webgl will serve?

    I'm kind of confused why you are doing rewrites? If the unity webgl build creates static files, you shouldn't have to use any rewrites?

    What are you running on IIS, is it ASP. NET web forms, MVC, if so what version of ASP MVC, etc.

    Or post a URL and I can take a look. That's just off the top of my head; I haven't used WebGL export yet so I'm not familiar with the different files it exports.
     
  3. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Hi, thanks.

    in the hidden under the scrollbar code I did that

    Code (csharp):
    1. .... stuff elided
    2.  
    3.      <staticContent>
    4.    <!-- AND MIME REGISTER THE TYPES //-->
    5.          <mimeMap fileExtension=".jsgz" mimeType="application/x-javascript" />
    6.        <mimeMap fileExtension=".datagz" mimeType="application/octet-stream" />
    7.        <mimeMap fileExtension=".memgz" mimeType="application/octet-stream" />
    8.        <mimeMap fileExtension=".unity3dgz" mimeType="application/octet-stream" />
    9.        <mimeMap fileExtension=".mem" mimeType="application/octet-stream" />
    10.        <mimeMap fileExtension=".data" mimeType="application/octet-stream" />
    11.      </staticContent>
    12. </system.webServer>
    13. </configuration>
    14.  
    that was my thought also.

    I do the rewrites as that is the unity way of doing things. as outlined in the top post in the section starting

    "and the .htaccess file (which is not IIS friendly directly but can be imported) says:"

    Thanks very much for answering though!!! I really appreciate any input.


    RE THE SERVER: Vanilla 2008 Datacenter edition. so.. .Net web forms I guess.
    I have full access to the servers configs.

     
    Last edited: Dec 6, 2014
    jonintendo, Meltdown and Graph like this.
  4. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
  5. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Yup, read that one.
    Tried it. Compression is on and working fine.

    Here is a quick precis

    this is what I did:

    1) Upload to server (I was not clear if I had to actually upload the two huge .mem and .data file in /DATA, from my reading of the rewrite rules below, "No, I do not have to" since all requests for those files will be redirected to their pre-compressed cousins. (but I did anyways to be sure)

    2) checked that the web.config was being honoured to serve out the .mem and .data stuff (I also actually tried hard-coding the MIME TYPES just for sanities sake, yup, web.config or hard coded is same) EDIT <--- ACTUALLY In the end I had to hard code them.

    3) Imported the rules into URL rewrite via the IMPORT RULES button and double checked they were sensible. They all seemed fine - 4 rules - redirecting unzipped requests to zipped equivalents. (they need little fix though as outlined in top post)

    4) Checked that the server has dynamic and static compression installed and enabled for the domain (which it does)

    5) revisited the .htaccess to see what I had missed.

    It's the final bit where in the .htaccess it would have been handled by:

    AddEncoding gzip .jsgz AddEncoding gzip .datagz AddEncoding gzip .memgz AddEncoding gzip .unity3dgz

    I /think/ it is this bit maybe where it goes wrong. Not sure how to do this is IIS?

    I will upload a tiny test project so people can see the errors. http://kaycare.co.uk/games/WebGL/
     
    Last edited: Dec 5, 2014
  6. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
  7. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    it looks like something must be messed up in the web.config. all static files are throwing 500's. you may want to turn on customErrors so you can see the IIS error.

    <customErrors mode="RemoteOnly"/>

    "RemoteOnly" will allow you to remote into the server and check the response, if it's a staging environment where you don't care, you can set it to "On"

     
  8. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Yup. Many thanks - I have fixed particular error now. It was a stray character in the xml. Doh

    However the real issue appears to be:

    HTTP Error 404.3 - Not Found
    The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.

    which I clearly have done.

    I will go hard code them in the IIS config instead and rip the web.config again. sigh.

    Thanks for looking. Driving me potato cakes
     
  9. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Okay so, Finally, I have the files serving.

    The STATIC section of the web.config was not being honored. Putting the MIME types into IIS finally allowed the files through BUT now they appear to not be being unencoded at my side.

    Sigh.

    application/x-javascript was the type I put on the .jsgz files.... is that wrong?

    UnityProgress.js:1 Uncaught SyntaxError: Unexpected token ILLEGAL
    UnityConfig.js:1 Uncaught SyntaxError: Unexpected token ILLEGAL
    fileloader.js:1 Uncaught SyntaxError: Unexpected token ILLEGAL
    WebGL.js:1 Uncaught SyntaxError: Unexpected token ILLEGAL

    Pretty sure that means I am being served the zipped js file now. and it isnt being parsed?

    gzippedJavascriptResponse.JPG
    The responses all look okay server side?

    and by accessing kaycare.co.uk/games/WebGL/data/fileloader.js you can now see a zipped version appearing...
     
  10. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    I just did a test WebGL build in ASP MVC 4 website:

    Due to the directory structure of MVC I changed some relative paths for "Data/" to "/Data/" in the index.html file that the webgl build spits out.

    As expected 403.4 errors on the MIME types that I have not configured in my web.config yet,


    Added the MIME maps to the web config:
    <staticContent>
    <mimeMap fileExtension=".data" mimeType="application/octet-stream" />
    <mimeMap fileExtension=".mem" mimeType="application/octet-stream" />
    </staticContent>

    That was enough to get the build running (albeit without compression)
    http://i.imgur.com/tjwUEWg.png

    For compression.. I'll try deploying to my shared web host, as I don't want to change IIS express configuration right now. I'm just using standard web.config compression, relevant web.config is as follows:

    Code (CSharp):
    1.   <system.webServer>
    2.  
    3. ..
    4.  
    5.     <staticContent>
    6.       <mimeMap fileExtension=".data" mimeType="application/octet-stream" />
    7.       <mimeMap fileExtension=".mem" mimeType="application/octet-stream" />
    8.     </staticContent>
    9.     <httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
    10.       <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll"/>
    11.       <dynamicTypes>
    12.         <add mimeType="text/*" enabled="true"/>
    13.         <add mimeType="message/*" enabled="true"/>
    14.         <add mimeType="application/javascript" enabled="true"/>
    15.         <add mimeType="*/*" enabled="true"/>
    16.       </dynamicTypes>
    17.       <staticTypes>
    18.         <add mimeType="text/*" enabled="true"/>
    19.         <add mimeType="message/*" enabled="true"/>
    20.         <add mimeType="application/javascript" enabled="true"/>
    21.         <add mimeType="*/*" enabled="true"/>
    22.       </staticTypes>
    23.     </httpCompression>
    24.     <urlCompression doStaticCompression="true" doDynamicCompression="true" />
    25.   </system.webServer>
    I pretty much picked that up off some website somewhere. I think this part should enable compression on everything..
    <add mimeType="*/*" enabled="true"/>

    and it appears to be gzipping and serving all the files,


    I'm not using any rewrites, I think that was specific to wahtever configuration the unity people were using. Although, I think my configuration is not using the files from the "compressed" directory. Those must be pre-gzipped or something. I've never done that, I've always had my web server do the gzipping and have the server cache the response. I'll have to see about that next..
     
    Last edited: Dec 5, 2014
  11. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    The rewrites are to enable the huge versions of the files to be replaced "pre-realtime" with the pre-zipped versions of the files. Since zipping 124mb everytime someone wanted to play your game would soon kill your server.

    (they should be in the compressed folder)

    Well, it sounds like I am right at the very verge of getting this thing working.

    Although I am back at exactly the same point I was when I started this thread.

    .jsgz files being served. Nothing else happening once they are returned. I must have them encoded wrong or something stupid. will keep digging then. thanks for your tips.

    NotUnzipped.JPG


    RE POST: Aye I remember that post from years ago, probably when I first did gzip stuff in my own apps.
    I have actually written custom http handlers in the past, - that used gzip - unbelievably, looking at the total lack of understanding going on today.

    Brain getting old. Will give this yet another go.
     
    Last edited: Dec 6, 2014
  12. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    i'll try to get it working with the compressed files, are you using ASP MVC?
     
  13. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Vanilla 2008 server. IIS 7.5, whatever came on that.

    Model View Controller? Errrr.... Honestly I don't know. Pretty sure that post dates the servers birthdate.

    I only use this box to shove out files and the occasional, very lightweight, Asp .Net programming job.
    It's just a file workhorse. Hence me being pretty unsure about its potential guts.

    EDIT: Hmm I seem to recall that stuff came out about a year after the server did. so I doubt it.
     
  14. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    I think the rewrites are not adding the correct HTTP header to the response, that should tell the browser it's using compression. It should be something like "content-encoding: gzip" or whatever.

    It seems like the browser doesn't realize that the response is gzipped, and it's getting all this crazy garbled gzipped javascript data that it can't understand. Therefore the "unexpected token" errors



    there's no content-encoding header in the response, so the browser just tries to read it without decompressing and it looks like this:

     
    Last edited: Dec 5, 2014
  15. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Yup, my thoughts too.

    Except it says here that I am sending that header back



    Quite the mystery.

    So I elided the bit of web.config trickery I posted in the top post, so as to NOT pass back the gzip header. Same thing. Not processed. gah :D

    I also tried the application/javascript type just in case.
     
  16. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    it still doesn't seem to be passing Content-Encoding header back to chrome at least. It's weird that it's working in firefox.. When you look at the response, does it look like javascript?
     
  17. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    nope, still junk. compressed junk.

    Code (csharp):
    1.  
    2.     <rewrite>
    3.          <outboundRules>
    4.              <rule name="Rewrite JSGZ header" preCondition="IsJSGZ" stopProcessing="false">
    5.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    6.                  <action type="Rewrite" value="gzip" />
    7.              </rule>
    8.             <rule name="Rewrite MemGZ header" preCondition="IsMemGZ" stopProcessing="false">
    9.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    10.                  <action type="Rewrite" value="gzip" />
    11.              </rule>
    12.               <rule name="Rewrite DataGZ header" preCondition="IsDataGZ" stopProcessing="false">
    13.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    14.                  <action type="Rewrite" value="gzip" />
    15.              </rule>
    16.             <rule name="Rewrite Unity3DGZ header" preCondition="IsUnity3DGZ" stopProcessing="false">
    17.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    18.                  <action type="Rewrite" value="gzip" />
    19.              </rule>
    20.             <preConditions>
    21.                  <preCondition name="IsJSGZ">
    22.                      <add input="{PATH_INFO}" pattern="\.jsgz$" />
    23.             </preCondition>
    24.                  <preCondition name="IsMemGZ">
    25.                      <add input="{PATH_INFO}" pattern="\.memgz$" />
    26.                  </preCondition>
    27.             <preCondition name="IsDataGZ">
    28.                      <add input="{PATH_INFO}" pattern="\.datagz$" />
    29.                  </preCondition>
    30.             <preCondition name="IsUnity3DGZ">
    31.                      <add input="{PATH_INFO}" pattern="\.unity3dgz$" />
    32.              </preCondition>
    33.              </preConditions>
    34.         </outboundRules>
    35.      </rewrite>
    36.  
    without those it does not send those gzip headers, period. so either that is somehow affecting the wrong output and I need to put it somewhere else.... Like in the main IIS config? I have zero idea how to do that though.
     
  18. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Last edited: Dec 6, 2014
  19. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    Well since those files are precompressed, maybe you should disable httpCompression on them in web config. It's possible they are getting double compressed.

    In which case the browser would decompress and itd still look like garbage.
     
    twobob likes this.
  20. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    ooh
    Good call. will try that..

    Sigh. Sadly not.

    Code (csharp):
    1.  
    2. <configuration>
    3. <system.webServer>
    4.         <urlCompression doStaticCompression="false" doDynamicCompression="false"/>
    5. ...
    6.  
    tried in all relevant locations, cache cleared between each or disabled as appropriate. Chrome/ff

    Really good thought though.
     
    Last edited: Dec 6, 2014
  21. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    Hm, just to make sure I'd try deleting web config, hit the site and make sure you get an error, then push web config again.. Or just restart site in IIS or something. I've had a few times where it was hanging onto certain web config settings.

    Probably not the problem, but just to make sure.

    I'll have to take a look again in a few mins when I'm back at a computer, that is a mystery for sure...
     
  22. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    sure thing.

    I'll go raze it to the ground and reboot the domain.
     
  23. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    did that. removed web.config, 404.3, added custom web.config with the gzip header handling included. 404.3 (that IS a mystery, checked it wasn't xml order related etc.),

    so reverted back to hard coded IIS management MIME types, that gets us past the 404.3 and onto the files being served but the response encoding being utterly ignored.

    Tried mangling the return content types, just broke stuff as expected, with pretty warnings.

    Did everything I could think of. went through all the configurations again. rebooted domain.

    In precis: Attempting to indicate .jsgz MIME type in the web.config after the URL rewrite fails on a 404.3 (as you saw), that is puzzling.

    Placing .jsgz in the default mime types and using the rewrite thing for the content headers looks like it works on paper but nothing happens on the client side for the unzipping.

    Totally befuddled.

    There HAS TO BE SOMEONE who has done this.
    Jeepers, it's so basic.
     
    Last edited: Dec 6, 2014
  24. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Well. I have even ripped the web.config completely now.

    and weirdly the server IS NOW appending the gzip to the response even without massage.

    an it STILL doesn't blumming work. So basically I have put on the files, added the MIME types to the main domain information, checked the responses are valid with the right headers.

    And it don't work. gah. out of ideas
     
  25. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    I read some people apparently have issues w/ stuff that uses "too high" of gzip compression, http://stackoverflow.com/questions/...-i-get-illegal-character-token-errors-in-both (bottom comment)

    The unity gzipped files looked like they were super-compressed; maybe it's running into errors because of the high compression or something. Or maybe unity's spitting out invalid compressed files. Who knows, it's a beta.

    Is this for a production game where you need super optimized compression? Can always skip the precompressed files, disable the rewrites, re-enable the httpCompression and use IIS built in gzipping, make sure it's using static compression so it can be cached in the browser. Admittedly it wasn't as compressed as those precompressed files, maybe like 25mb instead of 15mb or whatever. On the fly compression may kind of tax the web server, I'm not sure if/how IIS caches those gzipped responses. I would hope if the web server is gzipping a static file, it caches it somewhere. I'm not sure.

    Precompressed would obviously be the best, but it's a beta (who knows), and it's friday, I kinda give up for now xD

    If you continue down the precompressed route, I'd try skipping unity's precompressed files and compressing them on your own. Just to rule that out. Or verify w/ someone that those precompressed files are working.
     
    Last edited: Dec 6, 2014
  26. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Yeah me too. Thanks dude. I too read that post about the super compression, In fact I think I've read like every relevant post on the first 30 pages of goggle results for several search terms.

    Fact is without the compression the files are ENORMOUS. VAST. that one project has just a CUBE and a PLANE in it.

    it comes in a nearly a quarter of a gig mate. hardly serviceable.
    over250mb.JPG

    I've raised a request with my hosts, maybe they will take pity on me.

    EDIT: They did not.


    and I have tried every type of build. lowest to highest. and its not compression its optimisation they do.
    I watched the hour long video about it earlier.

    :\

    Have a great w/e!! :D



    .
     
    Last edited: Dec 9, 2014
  27. Caio_Lib

    Caio_Lib

    Joined:
    Mar 4, 2014
    Posts:
    79
    Hi, I'm using IIS server.
    I built a test game to see if I can help, it's just a cube and works ( worked using both optimization 'slow' and 'fastest', fastest is used now ):
    http://www.liberalistudios.com/trabalhos/webgl/example/

    My web.config:
    Code (CSharp):
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <configuration>
    3.     <system.webServer>
    4.         <staticContent>
    5.             <remove fileExtension=".mem" />
    6.             <mimeMap fileExtension=".mem" mimeType="application/octet-stream" />
    7.             <remove fileExtension=".data" />
    8.             <mimeMap fileExtension=".data" mimeType="application/octet-stream" />      
    9.         </staticContent>
    10.     </system.webServer>
    11. </configuration>
    Is based on TDMIsh answer: http://forum.unity3d.com/threads/how-to-properly-host-webgl-content.282364/
    Even deleting .htaccess file it's working.

    I thought you were using MVC or friendly url but your site seems to be using just html. ( http://kaycare.co.uk/index.html )
    What I would suggest to you is:
    - If you're not using ASP NET to backup and replace your web.config with the one above.
    - Test a build using just a cube
    - If using just a cube and web.config works but your game doesn't I think it is the compression problem that you're saying!

    Hope it helps, or at least give you some light!
     
    twobob likes this.
  28. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    Right - I mean as a temporary workaround for the issue with the precompressed files, you could skip using them and have IIS gzip the raw ones. The total size of downloading this empty build with IIS gzipping it was 31.9MB. IIS was still able to gzip it pretty well. Not as good as pre-compressed, but still fairly compressed.

    (in chrome "size" is the size downloaded, "content" is the actual uncompressed size of the file - so IIS gzip compressed build.js from 108mb down to 26.5mb)

    I did the webgl build on my computer at work, so I forget how big the precompressed files were, I think they were only slightly smaller.

     
    Last edited: Dec 6, 2014
    twobob likes this.
  29. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    Thanks for the thoughts people.

    My hosts were ultimately unhelpful. so I kept digging.

    I managed to find this in the new firefox developer toolbar.
    "The character encoding of the plain text document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the file needs to be declared in the transfer protocol or file needs to use a byte order mark as an encoding signature."

    So I am looking into that next, tried disabling Dynamic and Static compression manually via IIS on the site too, so it's not that. :\ another day, another segfault
     
  30. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    1,763
    So... A combination of

    Code (csharp):
    1.  
    2. <?xml version="1.0" encoding="UTF-8"?>
    3. <configuration>
    4. <system.webServer>
    5.      <rewrite>
    6.          <outboundRules>
    7.         <!-- FIRST SETUP THE SWITCHES FOR THE RESPONSE ENCODING //-->
    8.              <rule name="Rewrite JSGZ header" preCondition="IsJSGZ" stopProcessing="false">
    9.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    10.                  <action type="Rewrite" value="gzip" />
    11.              </rule>
    12.             <rule name="Rewrite MemGZ header" preCondition="IsMemGZ" stopProcessing="false">
    13.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    14.                  <action type="Rewrite" value="gzip" />
    15.              </rule>
    16.               <rule name="Rewrite DataGZ header" preCondition="IsDataGZ" stopProcessing="false">
    17.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    18.                  <action type="Rewrite" value="gzip" />
    19.              </rule>
    20.             <rule name="Rewrite Unity3DGZ header" preCondition="IsUnity3DGZ" stopProcessing="true">
    21.                  <match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
    22.                  <action type="Rewrite" value="gzip" />
    23.              </rule>
    24.              <!-- AND SETUP THE MATCHES FOR THE RESPONSE ENCODING SWITCHES //-->
    25.             <preConditions>
    26.                  <preCondition name="IsJSGZ">
    27.                      <add input="{PATH_INFO}" pattern="\.jsgz$" />
    28.             </preCondition>
    29.                  <preCondition name="IsMemGZ">
    30.                      <add input="{PATH_INFO}" pattern="\.memgz$" />
    31.                  </preCondition>
    32.             <preCondition name="IsDataGZ">
    33.                      <add input="{PATH_INFO}" pattern="\.datagz$" />
    34.                  </preCondition>
    35.             <preCondition name="IsUnity3DGZ">
    36.                      <add input="{PATH_INFO}" pattern="\.unity3dgz$" />
    37.                  </preCondition>
    38.              </preConditions>
    39.         </outboundRules>
    40.      </rewrite>
    41. </system.webServer>
    42. </configuration>
    43.  
    plus, DISABLING dynamic compression (manually, not in the config)

    and manually adding the (entire list of 5) types to the MIME register

    and adding
    application/x-javascript; charset=UTF-8
    to the MIME information of jsgz.

    appears to have done the job!!!!!!
    WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOTage.!!!!!!
    Still checking but heck I can see real script content where there was only compressed noise before. That has to work... testing now.

    EDIT: Yup files being served. I'll see if I can get it to work without the hardcoding....
     
    Last edited: Dec 6, 2014
    philwinkel likes this.
  31. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    Nice, glad you got that figured out! What an ordeal...

    Next week I think I'm gonna attack it from a different angle. I like to try and configure things in web.config and code as opposed to IIS stuff.. I'm gonna try to route the requests for the unity JS / MEM / DATA files to an MVC action... which would contain code that does the same thing that those URL rewrites are doing (check if the request headers indicate the browser supports compression, and serve out the correct precompressed file).

    I believe you can route requests for specific directory/file paths to ASP MVC actions instead of having IIS serve them out as static files, by configuring system.webServer handlers in the web.config, and then set up some MVC routes that catch the requests for those files.

    (I think it's also probably possible to do with a regular ASP .NET webforms project, but I'm not a big fan.. gotta have my MVC)

    My goal is basically to get it set up so you can just drop the unity WebGL build into the root of the website and have it work, without having to change stuff in IIS.


    Once again tho, nice work! I'm sure people trying to host on a windows server will find this helpful.
     
  32. philwinkel

    philwinkel

    Joined:
    Jun 6, 2013
    Posts:
    298
    Just tried the alternate solution I mentioned in the above post, and it seems to work. I haven't thought through all the possible implications of doing this instead of the IIS rewrite.

    Example project download (VS2013 community, ASP MVC 5, .NET 4.5):
    https://mega.co.nz/#!0tYRGbDL!oH2iLb-6H2KX1UnMHyNhC3ualfp_tFnoqNvg81FN0fE

    Workflow is basically: do your WebGL build, then copy it into the root of this ASP MVC website. As long as IIS is configured correctly to host the website (integrated pipeline, .NET 4.5), it should work without any IIS configuration changes or rewrite rules.

    Some details of the implementation:

    1. Disable IIS serving out the static JS, MEM, and DATA files, but only for the /Data/ directory. Add system.webServer handlers to web.config:

    Code (CSharp):
    1.   <system.webServer>
    2. ...
    3.     <handlers>
    4.       <!-- create handlers so requests to the Unity WebGL static files get routed through ASP MVC -->
    5.       <add name="UnityJSHandler" path="Data/*.js" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    6.       <add name="UnityMemHandler" path="Data/*.mem" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    7.       <add name="UnityDataHandler" path="Data/*.data" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    8.     </handlers>
    With those handlers in place, IIS won't serve out the static files in the Data/ directory.

    2. Next, configure MVC routing in RouteConfig.cs. Catch the requests for static files in the Data directory, and send them to the UnityStaticFile controller's Index action, with the requested file name as a parameter.

    Code (CSharp):
    1.     public class RouteConfig
    2.     {
    3.         public static void RegisterRoutes(RouteCollection routes)
    4.         {
    5.             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    6.  
    7.             // unity static file route handler. routes requests to /data/ js mem data files to UnityStaticFile controller's Index action
    8.             routes.RouteExistingFiles = true;
    9.  
    10.             routes.MapRoute(
    11.                 "UnityStaticFiles",
    12.                 "Data/{*file}",
    13.                 new {Controller = "UnityStaticFile", action = "Index"});
    14.  
    15.             routes.MapRoute(
    16.                 name: "Default",
    17.                 url: "{controller}/{action}/{id}",
    18.                 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    19.             );
    20.         }
    21.     }

    3. Configure UnityStaticFile controller to serve the correct files depending on the Request's accept-encoding header:

    Code (CSharp):
    1.     public class UnityStaticFileController : Controller
    2.     {
    3.         [OutputCache(Duration = 1200, VaryByHeader = "Accept-Encoding")]
    4.         public ActionResult Index(string file)
    5.         {
    6.             var acceptEncoding = Request.Headers.AllKeys.FirstOrDefault(key => key.ToLower() == "accept-encoding");
    7.  
    8.             // if no accept encoding header, return raw file (eww)
    9.             if (acceptEncoding == null)
    10.                 return new FilePathResult("/Data/" + file, getContentType(file));
    11.  
    12.             // if accept encoding gzip, return compressed files
    13.             if (Request.Headers[acceptEncoding].Contains("gzip"))
    14.             {
    15.                 Response.Headers.Add("Content-Encoding", "gzip");
    16.                 return new FilePathResult("/Compressed/" + file + "gz", getContentType(file));
    17.             }
    18.  
    19.             // bad request
    20.             return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
    21.         }
    22.  
    23.         private string getContentType(string file)
    24.         {
    25.             var ext = Path.GetExtension(file);
    26.             if (ext.Contains("js"))
    27.                 return "text/javascript; charset=UTF-8";
    28.  
    29.             // else
    30.             return "application/x-octet-stream";
    31.         }
    32.     }
    Code is kind of hacked together, but it basically does the same thing that those IIS rewrites are doing - if there is no "accept-encoding" header, it just serves the non-gzipped files. If there is an "accept-encoding: gzip" header, it sets the "Response Content-Encoding: gzip" header, and returns the compressed file. I'm using an [OutputCache] attribute to enable caching, with the VaryByHeader set to Accept-Encoding, so it should serve a cached response correctly depending on the Accept-Encoding header. (disclaimer: I have not fully tested, but the code path returning the compressed files worked for me in chrome)

    4. I set up the Home controller's Index action (it handles requests to the website root) to just serve the index.html file. So it's not using an ASP MVC view. This just basically serves the index.html file (in an ASP MVC way..) when you hit the root of the website.

    5. Side note, if running localhost in Visual Studio you may need to disable Browser Link, or it'll throw Out of Memory exceptions on huge static javascript files:


    Seems to be working:

     
    Last edited: Dec 7, 2014
    twobob likes this.