Merge branch 'upstream'
diff --git a/.travis.yml b/.travis.yml
index 60783fd..8de93ab 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,7 @@
 notifications:
   email: false
 otp_release:
+  - 21.0
   - 20.0
   - 19.0
   - 18.3
diff --git a/CHANGES.md b/CHANGES.md
index 6653723..7fd273e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,8 @@
+Version 2.18.0 released 2018-05-12
+
+* Add the 100.64.0.0/10 private IP shared address range
+  https://github.com/mochi/mochiweb/pull/193
+
 Version 2.17.0 released 2017-08-12
 
 * Fix deprecation warnings for Erlang/OTP 20.0
diff --git a/examples/hmac_api/hmac_api_lib.erl b/examples/hmac_api/hmac_api_lib.erl
index 6d04954..95d7c58 100644
--- a/examples/hmac_api/hmac_api_lib.erl
+++ b/examples/hmac_api/hmac_api_lib.erl
@@ -5,6 +5,8 @@
 
 -author("Hypernumbers Ltd <gordon@hypernumbers.com>").
 
+-compile(tuple_calls).
+
 %%% this library supports the hmac_sha api on both the client-side
 %%% AND the server-side
 %%%
diff --git a/examples/https/https_store.erl b/examples/https/https_store.erl
index 959cc00..23e2447 100644
--- a/examples/https/https_store.erl
+++ b/examples/https/https_store.erl
@@ -34,6 +34,8 @@
 
 -module(https_store).
 
+-compile(tuple_calls).
+
 -export([start/0,
          stop/0,
          dispatch/1,
diff --git a/examples/keepalive/keepalive.erl b/examples/keepalive/keepalive.erl
index 965a17e..a371e91 100644
--- a/examples/keepalive/keepalive.erl
+++ b/examples/keepalive/keepalive.erl
@@ -1,5 +1,7 @@
 -module(keepalive).
 
+-compile(tuple_calls).
+
 %% your web app can push data to clients using a technique called comet long
 %% polling.  browsers make a request and your server waits to send a
 %% response until data is available.  see wikipedia for a better explanation:
diff --git a/src/mochifmt.erl b/src/mochifmt.erl
index 6381bb7..5a5ed45 100644
--- a/src/mochifmt.erl
+++ b/src/mochifmt.erl
@@ -24,6 +24,9 @@
 %%
 -module(mochifmt).
 -author('bob@mochimedia.com').
+
+-compile(tuple_calls).
+
 -export([format/2, format_field/2, convert_field/2, get_value/2, get_field/2]).
 -export([tokenize/1, format/3, get_field/3, format_field/3]).
 -export([bformat/2, bformat/3]).
diff --git a/src/mochiweb.app.src b/src/mochiweb.app.src
index 6bcdd5a..60f15f5 100644
--- a/src/mochiweb.app.src
+++ b/src/mochiweb.app.src
@@ -1,7 +1,7 @@
 %% This is generated from src/mochiweb.app.src
 {application, mochiweb,
  [{description, "MochiMedia Web Server"},
-  {vsn, "2.17.0"},
+  {vsn, "2.18.0"},
   {modules, []},
   {registered, []},
   {env, []},
diff --git a/src/mochiweb_acceptor.erl b/src/mochiweb_acceptor.erl
index 44ce91f..3fd6925 100644
--- a/src/mochiweb_acceptor.erl
+++ b/src/mochiweb_acceptor.erl
@@ -24,6 +24,8 @@
 -module(mochiweb_acceptor).
 -author('bob@mochimedia.com').
 
+-compile(tuple_calls).
+
 -include("internal.hrl").
 
 -export([start_link/3, start_link/4, init/4]).
diff --git a/src/mochiweb_cookies.erl b/src/mochiweb_cookies.erl
index 9539041..013dbe0 100644
--- a/src/mochiweb_cookies.erl
+++ b/src/mochiweb_cookies.erl
@@ -52,6 +52,7 @@
 %% where Option = {max_age, int_seconds()} | {local_time, {date(), time()}}
 %%                | {domain, string()} | {path, string()}
 %%                | {secure, true | false} | {http_only, true | false}
+%%                | {same_site, lax | strict}
 %%
 %% @doc Generate a Set-Cookie header field tuple.
 cookie(Key, Value, Options) ->
@@ -109,7 +110,17 @@
             _ ->
                 ""
         end,
-    CookieParts = [Cookie, ExpiresPart, SecurePart, DomainPart, PathPart, HttpOnlyPart],
+    SameSitePart =
+        case proplists:get_value(same_site, Options) of
+            undefined ->
+                "";
+            lax ->
+                "; SameSite=Lax";
+            strict ->
+                "; SameSite=Strict"
+        end,
+    CookieParts = [Cookie, ExpiresPart, SecurePart, DomainPart, PathPart,
+        HttpOnlyPart, SameSitePart],
     {"Set-Cookie", lists:flatten(CookieParts)}.
 
 
diff --git a/src/mochiweb_http.erl b/src/mochiweb_http.erl
index 3b02065..a4bfa9e 100644
--- a/src/mochiweb_http.erl
+++ b/src/mochiweb_http.erl
@@ -28,6 +28,8 @@
 -export([after_response/2, reentry/1]).
 -export([parse_range_request/1, range_skip_length/2]).
 
+-compile(tuple_calls).
+
 -define(REQUEST_RECV_TIMEOUT, 300000).   %% timeout waiting for request line
 -define(HEADERS_RECV_TIMEOUT, 30000).    %% timeout waiting for headers
 
@@ -41,6 +43,8 @@
 r15b_workaround() -> false.
 -endif.
 
+
+
 parse_options(Options) ->
     {loop, HttpLoop} = proplists:lookup(loop, Options),
     Loop = {?MODULE, loop, [HttpLoop]},
diff --git a/src/mochiweb_multipart.erl b/src/mochiweb_multipart.erl
index fd75443..6f611c0 100644
--- a/src/mochiweb_multipart.erl
+++ b/src/mochiweb_multipart.erl
@@ -24,6 +24,8 @@
 -module(mochiweb_multipart).
 -author('bob@mochimedia.com').
 
+-compile(tuple_calls).
+
 -export([parse_form/1, parse_form/2]).
 -export([parse_multipart_request/2]).
 -export([parts_to_body/3, parts_to_multipart_body/4]).
diff --git a/src/mochiweb_request.erl b/src/mochiweb_request.erl
index ec0ad36..240f043 100644
--- a/src/mochiweb_request.erl
+++ b/src/mochiweb_request.erl
@@ -24,6 +24,8 @@
 -module(mochiweb_request).
 -author('bob@mochimedia.com').
 
+-compile(tuple_calls).
+
 -include_lib("kernel/include/file.hrl").
 -include("internal.hrl").
 
@@ -127,6 +129,14 @@
                 Hosts ->
                     string:strip(lists:last(string:tokens(Hosts, ",")))
             end;
+        %% According to RFC 6598, contributor Gerald Xv
+        {ok, {Addr={100, Second, _, _}, _Port}} when (Second > 63) andalso (Second < 128) ->
+            case get_header_value("x-forwarded-for", THIS) of
+                undefined ->
+                    inet_parse:ntoa(Addr);
+                Hosts ->
+                    string:strip(lists:last(string:tokens(Hosts, ",")))
+            end;
         {ok, {Addr={192, 168, _, _}, _Port}} ->
             case get_header_value("x-forwarded-for", THIS) of
                 undefined ->
diff --git a/src/mochiweb_response.erl b/src/mochiweb_response.erl
index 195e652..dc9569e 100644
--- a/src/mochiweb_response.erl
+++ b/src/mochiweb_response.erl
@@ -24,6 +24,8 @@
 -module(mochiweb_response).
 -author('bob@mochimedia.com').
 
+-compile(tuple_calls).
+
 -define(QUIP, "Any of you quaids got a smint?").
 
 -export([new/3, get_header_value/2, get/2, dump/1]).
diff --git a/src/mochiweb_socket.erl b/src/mochiweb_socket.erl
index 1756b8e..cbce78a 100644
--- a/src/mochiweb_socket.erl
+++ b/src/mochiweb_socket.erl
@@ -144,5 +144,7 @@
 
 exit_if_closed({error, closed}) ->
     exit(normal);
+exit_if_closed({error, einval}) ->
+    exit(normal);
 exit_if_closed(Res) ->
     Res.
diff --git a/src/mochiweb_websocket.erl b/src/mochiweb_websocket.erl
index 14b242a..690c91f 100644
--- a/src/mochiweb_websocket.erl
+++ b/src/mochiweb_websocket.erl
@@ -25,6 +25,8 @@
 
 %% @doc Websockets module for Mochiweb. Based on Misultin websockets module.
 
+-compile(tuple_calls).
+
 -export([loop/5, upgrade_connection/2, request/5]).
 -export([send/3]).
 -ifdef(TEST).
diff --git a/support/templates/mochiwebapp_skel/src/mochiapp_web.erl b/support/templates/mochiwebapp_skel/src/mochiapp_web.erl
index 8429a88..7ffb44d 100644
--- a/support/templates/mochiwebapp_skel/src/mochiapp_web.erl
+++ b/support/templates/mochiwebapp_skel/src/mochiapp_web.erl
@@ -6,6 +6,8 @@
 -module({{appid}}_web).
 -author("{{author}}").
 
+-compile(tuple_calls).
+
 -export([start/1, stop/0, loop/2]).
 
 %% External API
diff --git a/test/mochiweb_http_tests.erl b/test/mochiweb_http_tests.erl
index 0003451..1057755 100644
--- a/test/mochiweb_http_tests.erl
+++ b/test/mochiweb_http_tests.erl
@@ -7,6 +7,8 @@
 -define(SHOULD_HAVE_BUG, false).
 -endif.
 
+-compile(tuple_calls).
+
 has_acceptor_bug_test_() ->
     {setup,
      fun start_server/0,
diff --git a/test/mochiweb_request_tests.erl b/test/mochiweb_request_tests.erl
index b40c867..b8f93e2 100644
--- a/test/mochiweb_request_tests.erl
+++ b/test/mochiweb_request_tests.erl
@@ -1,5 +1,7 @@
 -module(mochiweb_request_tests).
 
+-compile(tuple_calls).
+
 -ifdef(TEST).
 -include_lib("eunit/include/eunit.hrl").
 
diff --git a/test/mochiweb_tests.erl b/test/mochiweb_tests.erl
index 23f8312..697f7c6 100644
--- a/test/mochiweb_tests.erl
+++ b/test/mochiweb_tests.erl
@@ -2,6 +2,8 @@
 -include_lib("eunit/include/eunit.hrl").
 -include("mochiweb_test_util.hrl").
 
+-compile(tuple_calls).
+
 with_server(Transport, ServerFun, ClientFun) ->
     mochiweb_test_util:with_server(Transport, ServerFun, ClientFun).
 
diff --git a/test/mochiweb_websocket_tests.erl b/test/mochiweb_websocket_tests.erl
index eb8de5b..71fb9a6 100644
--- a/test/mochiweb_websocket_tests.erl
+++ b/test/mochiweb_websocket_tests.erl
@@ -23,6 +23,8 @@
 %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 %% THE SOFTWARE.
 
+-compile(tuple_calls).
+
 -include_lib("eunit/include/eunit.hrl").
 
 make_handshake_for_correct_client_test() ->