Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add improved response headers #59

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions worker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {getRenderer} from './wasm';
import PromiseGatherer from "./promise_gather";
import {CachedMojangApiService, DirectMojangApiService} from "./services/mojang/api";
import { default as CACHE_BUST } from './util/cache-bust';
import { EMPTY } from "./data";

self.addEventListener('fetch', (event: FetchEvent) => {
event.respondWith(handleRequest(event));
Expand Down Expand Up @@ -109,14 +108,6 @@ async function processRequest(skinService: MojangRequestService, interpreted: Cr
}
case RequestedKind.Cape: {
const cape = await skinService.retrieveCape(interpreted, gatherer);
if (cape.status === 404) {
return new Response(EMPTY, {
status: 404,
headers: {
'X-Crafthead-Profile-Cache-Hit': 'invalid-profile'
}
});
}
return renderImage(cape, interpreted);
}
default:
Expand Down
75 changes: 47 additions & 28 deletions worker/services/mojang/service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// <reference path="./mojang.d.ts">

import PromiseGatherer from '../../promise_gather';
import { IdentityKind, CraftheadRequest, TextureKind } from '../../request';
import { ALEX_SKIN, STEVE_SKIN } from '../../data';
import { IdentityKind, CraftheadRequest, RequestedKind, TextureKind } from '../../request';
import { ALEX_SKIN, EMPTY, STEVE_SKIN } from '../../data';
import { MojangApiService, MojangProfile, MojangProfileProperty } from "./api";
import { CacheComputeResult } from '../../util/cache-helper';
import { fromHex, javaHashCode, offlinePlayerUuid, toHex, uuidVersion } from '../../util/uuid';
Expand Down Expand Up @@ -60,7 +60,7 @@ export default class MojangRequestService {
/**
* Fetches a texture directly from the Mojang servers. Assumes the request has been normalized already.
*/
private async retrieveTextureDirect(request: CraftheadRequest, gatherer: PromiseGatherer, kind: TextureKind): Promise<Response> {
private async retrieveTextureDirect(request: CraftheadRequest, gatherer: PromiseGatherer, kind: TextureKind): Promise<TextureResponse> {
const rawUuid = fromHex(request.identity);
if (uuidVersion(rawUuid) === 4) {
const lookup = await this.mojangApi.fetchProfile(request.identity, gatherer);
Expand All @@ -69,39 +69,39 @@ export default class MojangRequestService {
if (textureResponse) {
const buff = await textureResponse.texture.arrayBuffer();
if (buff && buff.byteLength > 0) {
return new Response(buff, {
const response = new Response(buff, {
status: 200,
headers: {
'X-Crafthead-Profile-Cache-Hit': lookup.source,
'X-Crafthead-Skin-Model': request.model || textureResponse.model || 'default'
}
headers: textureResponse.texture.headers
});
response.headers.set('X-Crafthead-Profile-Cache-Hit', lookup.source);

return {
texture: response,
model: textureResponse.model
};
}
}
return new Response(STEVE_SKIN, {
return { texture: new Response(STEVE_SKIN, {
status: 404,
headers: {
'X-Crafthead-Profile-Cache-Hit': 'not-found',
'X-Crafthead-Skin-Model': 'default'
'X-Crafthead-Profile-Cache-Hit': 'not-found'
}
});
}) };
}
return new Response(STEVE_SKIN, {
return { texture: new Response(STEVE_SKIN, {
status: 404,
headers: {
'X-Crafthead-Profile-Cache-Hit': 'not-found',
'X-Crafthead-Skin-Model': 'default'
'X-Crafthead-Profile-Cache-Hit': 'not-found'
}
});
}) };
}

return new Response(STEVE_SKIN, {
return { texture: new Response(STEVE_SKIN, {
status: 404,
headers: {
'X-Crafthead-Profile-Cache-Hit': 'offline-mode',
'X-Crafthead-Skin-Model': 'default'
'X-Crafthead-Profile-Cache-Hit': 'offline-mode'
}
});
}) };
}

async retrieveSkin(request: CraftheadRequest, gatherer: PromiseGatherer): Promise<Response> {
Expand All @@ -112,31 +112,43 @@ export default class MojangRequestService {

const normalized = await this.normalizeRequest(request, gatherer);
const skin = await this.retrieveTextureDirect(normalized, gatherer, TextureKind.SKIN);
if (skin.status === 404) {
if (skin.texture.status === 404) {
// Offline mode ID (usually when we have a username and the username isn't valid)
const rawUuid = fromHex(normalized.identity);
if (Math.abs(javaHashCode(rawUuid)) % 2 == 0) {
return new Response(STEVE_SKIN, {
headers: {
'X-Crafthead-Profile-Cache-Hit': 'invalid-profile',
'X-Crafthead-Skin-Model': 'default'
'X-Crafthead-Profile-Cache-Hit': 'invalid-profile'
}
});
} else {
return new Response(ALEX_SKIN, {
headers: {
'X-Crafthead-Profile-Cache-Hit': 'invalid-profile',
'X-Crafthead-Skin-Model': 'slim'
'X-Crafthead-Profile-Cache-Hit': 'invalid-profile'
}
});
}
}
return skin;

if ([RequestedKind.Skin, RequestedKind.Body, RequestedKind.Bust].includes(normalized.requested)) {
skin.texture.headers.set('X-Crafthead-Skin-Model', request.model || skin.model || 'default');
}

return skin.texture;
}

async retrieveCape(request: CraftheadRequest, gatherer: PromiseGatherer): Promise<Response> {
const normalized = await this.normalizeRequest(request, gatherer);
return this.retrieveTextureDirect(normalized, gatherer, TextureKind.CAPE);
const cape = await this.retrieveTextureDirect(normalized, gatherer, TextureKind.CAPE);
if (cape.texture.status === 404) {
return new Response(EMPTY, {
status: 404,
headers: {
'X-Crafthead-Profile-Cache-Hit': 'invalid-profile'
}
});
}
return cape.texture;
}

private static async fetchTextureFromProfile(profile: MojangProfile, type: TextureKind): Promise<TextureResponse | undefined> {
Expand All @@ -160,7 +172,14 @@ export default class MojangRequestService {
}

console.log("Successfully retrieved texture");
return { texture: textureResponse, model: texturesData?.SKIN?.metadata?.model };

const response = new Response(textureResponse.body);
const textureID = textureUrl.split('/').pop();
if (textureID) {
response.headers.set("X-Crafthead-Texture-ID", textureID)
}

return { texture: response, model: texturesData?.SKIN?.metadata?.model };
}
}

Expand Down