expo / custom-expo-updates-server

238 stars 67 forks source link

Asset URL incompatibility with iOS client when running server on Windows #26

Open j005u opened 1 year ago

j005u commented 1 year ago

When running expo-updates-server natively on Windows asset URLs get a path with some backslashes like /api/assets?asset=updates\1.0.0\1675941667/assets/62c0135163427c652ae397f327f85010&runtimeVersion=1.0.0&platform=ios.

NSURL in iOS does not like this, which results in asset URLs becoming nil and the update failing "due to missing asset URL".

I solved this for myself by moving to WSL for expo-updates-server, but figured maybe some path normalization could be in order?

jake-carpenter commented 1 year ago

I ended up making a change to that function to URL encode any backslash (windows path). I agree that it could be handled better though. This isn't the first time I had been bitten by different string handling in URLs between iOS and Android either.

export async function getAssetMetadataAsync(arg: GetAssetMetadataArg) {
  const assetFilePath = `${arg.updateBundlePath}/${arg.filePath}`;
  const asset = await fs.readFile(path.resolve(assetFilePath), null);

  // On Windows, the path can include backslashes doubled up, which causes iOS to not work.
  // Android continues to work. This will simply replace '\\' with URL encoded '\'
  const assetFilePathClean = assetFilePath.replace(/\\/g, '%5C');

  const assetHash = getBase64URLEncoding(createHash(asset, 'sha256', 'base64'));
  const key = createHash(asset, 'md5', 'hex');
  const keyExtensionSuffix = arg.isLaunchAsset ? 'bundle' : arg.ext;
  const contentType = arg.isLaunchAsset ? 'application/javascript' : mime.getType(arg.ext);

  return {
    hash: assetHash,
    key,
    fileExtension: `.${keyExtensionSuffix}`,
    contentType,
    url: `${process.env.BASE_URL}?asset=${assetFilePathClean}&runtimeVersion=${arg.runtimeVersion}&platform=${arg.platform}`,
  };
}