Skip to content

Commit

Permalink
Handle null tokens in odsp driver. (#5010)
Browse files Browse the repository at this point in the history
  • Loading branch information
jatgarg authored Feb 5, 2021
1 parent 3c7d7c9 commit 3a9d350
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 3 deletions.
8 changes: 7 additions & 1 deletion packages/drivers/odsp-driver/src/odspDocumentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
IDocumentStorageService,
} from "@fluidframework/driver-definitions";
import { canRetryOnError } from "@fluidframework/driver-utils";
import { fetchTokenErrorCode } from "@fluidframework/odsp-doclib-utils";
import {
IClient,
IErrorTrackingService,
Expand All @@ -38,6 +39,7 @@ import { fetchJoinSession } from "./vroom";
import { isOdcOrigin } from "./odspUrlHelper";
import { TokenFetchOptions } from "./tokenFetch";
import { EpochTracker } from "./epochTracker";
import { throwOdspNetworkError } from "./odspError";

const afdUrlConnectExpirationMs = 6 * 60 * 60 * 1000; // 6 hours
const lastAfdConnectionTimeMsKey = "LastAfdConnectionTimeMs";
Expand Down Expand Up @@ -257,12 +259,16 @@ export class OdspDocumentService implements IDocumentService {
throw new Error("websocket endpoint should be defined");
}

const finalSocketToken = webSocketToken ?? (websocketEndpoint.socketToken || null);
if (finalSocketToken === null) {
throwOdspNetworkError("Push Token is null", fetchTokenErrorCode);
}
try {
const connection = await this.connectToDeltaStreamWithRetry(
websocketEndpoint.tenantId,
websocketEndpoint.id,
// Accounts for ODC where websocket token is returned as part of joinsession response payload
webSocketToken ?? (websocketEndpoint.socketToken || null),
finalSocketToken,
io,
client,
websocketEndpoint.deltaStreamSocketUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
PerformanceEvent,
} from "@fluidframework/telemetry-utils";
import { ensureFluidResolvedUrl } from "@fluidframework/driver-utils";
import { fetchTokenErrorCode, throwOdspNetworkError } from "@fluidframework/odsp-doclib-utils";
import { IOdspResolvedUrl, HostStoragePolicy } from "./contracts";
import {
LocalPersistentCache,
Expand Down Expand Up @@ -155,8 +156,12 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
},
async (event) => tokenFetcher(resolvedUrl.siteUrl, options.refresh, options.claims)
.then((tokenResponse) => {
event.end({ fromCache: isTokenFromCache(tokenResponse) });
return tokenFromResponse(tokenResponse);
const token = tokenFromResponse(tokenResponse);
event.end({ fromCache: isTokenFromCache(tokenResponse), isNull: token === null ? true : false });
if (token === null) {
throwOdspNetworkError("Storage Token is null", fetchTokenErrorCode);
}
return token;
}));
};
}
Expand Down
3 changes: 3 additions & 0 deletions packages/drivers/odsp-driver/src/odspUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
offlineFetchFailureStatusCode,
fetchFailureStatusCode,
fetchTimeoutStatusCode,
OdspErrorType,
} from "@fluidframework/odsp-doclib-utils";
import {
default as fetch,
Expand Down Expand Up @@ -48,6 +49,8 @@ export async function getWithRetryForTokenRefresh<T>(get: (options: TokenFetchOp
return get({ refresh: true, claims: e.claims });
// fetchIncorrectResponse indicates some error on the wire, retry once.
case DriverErrorType.incorrectServerResponse:
// If the token was null, then retry once.
case OdspErrorType.fetchTokenError:
return get({ refresh: true });
default:
// All code paths (deltas, blobs, trees) already throw exceptions.
Expand Down
7 changes: 7 additions & 0 deletions packages/utils/odsp-doclib-utils/src/odspErrorUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export const fetchTimeoutStatusCode = 713;
// with the server epoch version, the server throws this error code.
// This indicates that the file/container has been modified externally.
export const fluidEpochMismatchError = 409;
// Error code for when the fetched token is null.
export const fetchTokenErrorCode = 724;

export enum OdspErrorType {
/**
Expand Down Expand Up @@ -64,6 +66,8 @@ export enum OdspErrorType {
* does not match the one at the server.
*/
epochVersionMismatch = "epochVersionMismatch",

fetchTokenError = "fetchTokenError",
}

/**
Expand Down Expand Up @@ -135,6 +139,9 @@ export function createOdspNetworkError(
case fetchTimeoutStatusCode:
error = new NonRetryableError(errorMessage, OdspErrorType.fetchTimeout, statusCode);
break;
case fetchTokenErrorCode:
error = new NonRetryableError(errorMessage, OdspErrorType.fetchTokenError, statusCode);
break;
default:
error = createGenericNetworkError(errorMessage, true, retryAfterSeconds, statusCode);
}
Expand Down

0 comments on commit 3a9d350

Please sign in to comment.