diff --git a/config.js b/config.js index 0c9bd2c..e524106 100644 --- a/config.js +++ b/config.js @@ -35,7 +35,9 @@ var config = { browser: parseInt(process.env.CACHE_BROWSER) || 3600, // If true, redis is flushed on start. // Use this to avoid issues when you have a persistent redis database but an ephemeral storage - ephemeral: process.env.EPHEMERAL_STORAGE === "true" || false, + ephemeral: process.env.EPHEMERAL_STORAGE === "true", + // Used for information on the front page + cloudflare: process.env.CLOUDFLARE === "true" }, // URL of your redis server redis: process.env.REDIS_URL || 'redis://localhost:6379', @@ -47,9 +49,9 @@ var config = { // ms until connection to Mojang is dropped http_timeout: parseInt(process.env.EXTERNAL_HTTP_TIMEOUT) || 2000, // enables logging.debug & editing index page - debug_enabled: process.env.DEBUG === "true" || false, + debug_enabled: process.env.DEBUG === "true", // set to false if you use an external logger that provides timestamps, - log_time: process.env.LOG_TIME === "true" || true, + log_time: process.env.LOG_TIME === "true", // rate limit per second for outgoing requests to the Mojang session server // requests exceeding this limit are skipped and considered failed sessions_rate_limit: parseInt(process.env.SESSIONS_RATE_LIMIT) || Infinity diff --git a/lib/helpers.js b/lib/helpers.js index fdbe479..65beef1 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -240,13 +240,13 @@ exp.get_image_hash = function(rid, userId, type, callback) { } store_images(rid, userId, cache_details, type, function(store_err, new_hash, slim) { if (store_err) { - // we might have a cached hash although an error occured + // an error occured, but we have a cached hash // (e.g. Mojang servers not reachable, using outdated hash) // when hitting the rate limit, let's pretend the request succeeded and bump the TTL var ratelimited = store_err.code === "RATELIMIT"; cache.update_timestamp(rid, userId, !ratelimited, function(err2) { - callback(err2 || store_err, -1, cache_details && cached_hash, slim); + callback(err2 || store_err, 4, cache_details && cached_hash, slim); }); } else { var status = cache_details && (cached_hash === new_hash) ? 3 : 2; diff --git a/lib/response.js b/lib/response.js index daf08cb..19148ca 100644 --- a/lib/response.js +++ b/lib/response.js @@ -3,12 +3,13 @@ var config = require("../config"); var crc = require("crc").crc32; var human_status = { - "-2": "user error", // e.g. invalid size - "-1": "server error", // e.g. mojang/network issues - 0: "none", // cached as null (user has no skin) - 1: "cached", // found on disk - 2: "downloaded", // profile downloaded, skin downloaded from mojang servers - 3: "checked", // profile re-downloaded (was too old), has no skin or skin cached + "-2": "user error", // e.g. invalid size + "-1": "server error", // e.g. mojang/network issues + 0: "none", // cached as null (user has no skin) + 1: "cached", // found on disk + 2: "downloaded", // profile downloaded, skin downloaded from mojang servers + 3: "checked", // profile re-downloaded (was too old), has no skin or skin cached + 4: "server error;cached" // tried to check but ran into server error, using cached version }; @@ -83,13 +84,24 @@ module.exports = function(request, response, result) { if (result.status === -2) { response.writeHead(result.code || 422, headers); } else if (result.status === -1) { - // 500 responses shouldn't be cached - headers["Cache-Control"] = "private, max-age=0, no-cache"; - response.writeHead(result.code || 500, headers); + // server errors shouldn't be cached + headers["Cache-Control"] = "no-cache, max-age=0"; + if (result.body && result.hash && !result.hash.startsWith("mhf_")) { + headers["Warning"] = '110 Crafatar "Response is Stale"' + headers["Etag"] = etag; + result.code = result.code || 200; + } + if (result.err && result.err.code === "ENOENT") { + result.code = result.code || 500; + } + response.writeHead(result.code || 502, headers); } else { if (result.body) { - headers.Etag = etag; - response.writeHead(result.status === 2 ? 201 : 200, headers); + if (result.status === 4) { + headers["Warning"] = '111 Crafatar "Revalidation Failed"' + } + headers["Etag"] = etag; + response.writeHead(200, headers); } else { response.writeHead(404, headers); } diff --git a/lib/views/index.html.ejs b/lib/views/index.html.ejs index 51deab0..4439fcb 100644 --- a/lib/views/index.html.ejs +++ b/lib/views/index.html.ejs @@ -76,6 +76,7 @@ +
You can use mcuuid.net to find the UUID of a username.
Crafatar checks for skin updates every <%= config.caching.local / 60 %> minutes.
- Images are cached in your browser for <%= config.caching.browser / 60 %> minutes until a new request to Crafatar is made.
- In addition, CloudFlare caches up to 2 hours on a per-url basis.
+ Images are also cached in your browser for <%= config.caching.browser / 60 %> minutes unless you clear your browser cache.
+ <% if (config.caching.cloudflare) { %>
+
In addition, Cloudflare may cache images as long as your browser would.
+ <% } %>
When you changed your skin you can try clearing your browser cache to see the change faster.
+After changing your Minecraft skin, you can try clearing your browser cache to see the change faster.
- Responses come with some custom HTTP headers, useful for debugging.
- Please note that these headers may be cached by CloudFlare.
+ Crafatar always replies with a 200 OK status code when the requested user's skin/cape was found. This is also used in some rare cases when Mojang servers are having issues and the image couldn't be checked for changes, but Crafatar still had a cached version. 502 Bad Gateway and 500 Server Error are used when no skin/cape was found because of Mojang or Crafatar server issues.
+
+ Note that requests are usually answered with an image (with Steve/Alex skin), even if an error occured! +
+
+ Responses come with some HTTP headers that are useful for debugging.
+ <% if (config.caching.cloudflare) { %>
+
Please note that these headers may be cached by Cloudflare.
+ <% } %>
110 Crafatar "Response is Stale"111 Crafatar "Revalidation Failed"