diff --git a/packages/bsky/src/api/app/bsky/actor/getSuggestions.ts b/packages/bsky/src/api/app/bsky/actor/getSuggestions.ts index af53508a359..34add3f7926 100644 --- a/packages/bsky/src/api/app/bsky/actor/getSuggestions.ts +++ b/packages/bsky/src/api/app/bsky/actor/getSuggestions.ts @@ -29,6 +29,9 @@ export default function (server: Server, ctx: AppContext) { const hydrateCtx = await ctx.hydrator.createContext({ viewer, labelers }) const headers = noUndefinedVals({ 'accept-language': req.headers['accept-language'], + 'x-bsky-topics': Array.isArray(req.headers['x-bsky-topics']) + ? req.headers['x-bsky-topics'].join(',') + : req.headers['x-bsky-topics'], }) const { resHeaders: resultHeaders, ...result } = await getSuggestions( { ...params, hydrateCtx, headers }, diff --git a/packages/bsky/src/api/app/bsky/feed/getFeed.ts b/packages/bsky/src/api/app/bsky/feed/getFeed.ts index 815a1cb671f..bbd479e1636 100644 --- a/packages/bsky/src/api/app/bsky/feed/getFeed.ts +++ b/packages/bsky/src/api/app/bsky/feed/getFeed.ts @@ -46,6 +46,9 @@ export default function (server: Server, ctx: AppContext) { const headers = noUndefinedVals({ authorization: req.headers['authorization'], 'accept-language': req.headers['accept-language'], + 'x-bsky-topics': Array.isArray(req.headers['x-bsky-topics']) + ? req.headers['x-bsky-topics'].join(',') + : req.headers['x-bsky-topics'], }) // @NOTE feed cursors should not be affected by appview swap const { diff --git a/packages/pds/src/api/app/bsky/actor/getSuggestions.ts b/packages/pds/src/api/app/bsky/actor/getSuggestions.ts index fadcac2e9fc..3eaac00d33b 100644 --- a/packages/pds/src/api/app/bsky/actor/getSuggestions.ts +++ b/packages/pds/src/api/app/bsky/actor/getSuggestions.ts @@ -9,7 +9,9 @@ export default function (server: Server, ctx: AppContext) { auth: ctx.authVerifier.access, handler: async ({ req, auth }) => { const requester = auth.credentials.did - return pipethrough(ctx, req, requester) + return pipethrough(ctx, req, requester, undefined, { + reqHeadersToForward: ['x-bsky-topics'], + }) }, }) } diff --git a/packages/pds/src/api/app/bsky/feed/getFeed.ts b/packages/pds/src/api/app/bsky/feed/getFeed.ts index 601dbba8eed..d9fd008fcb7 100644 --- a/packages/pds/src/api/app/bsky/feed/getFeed.ts +++ b/packages/pds/src/api/app/bsky/feed/getFeed.ts @@ -16,7 +16,9 @@ export default function (server: Server, ctx: AppContext) { { feed: params.feed }, await ctx.appviewAuthHeaders(requester), ) - return pipethrough(ctx, req, requester, feed.view.did) + return pipethrough(ctx, req, requester, feed.view.did, { + reqHeadersToForward: ['x-bsky-topics'], + }) }, }) } diff --git a/packages/pds/src/pipethrough.ts b/packages/pds/src/pipethrough.ts index 59998d5b81b..4f54e1f84aa 100644 --- a/packages/pds/src/pipethrough.ts +++ b/packages/pds/src/pipethrough.ts @@ -9,6 +9,14 @@ import { httpLogger } from './logger' import { getServiceEndpoint, noUndefinedVals } from '@atproto/common' import AppContext from './context' +type PipethroughOptions = { + /** + * Request headers to pass-through, in addition to those defined in + * {@link REQ_HEADERS_TO_FORWARD} + */ + reqHeadersToForward?: string[] +} + const defaultService = ( ctx: AppContext, path: string, @@ -39,12 +47,14 @@ export const pipethrough = async ( req: express.Request, requester?: string, audOverride?: string, + options?: PipethroughOptions, ): Promise => { const { url, headers } = await createUrlAndHeaders( ctx, req, requester, audOverride, + options, ) const reqInit: RequestInit = { headers, @@ -106,6 +116,7 @@ export const createUrlAndHeaders = async ( req: express.Request, requester?: string, audOverride?: string, + options?: PipethroughOptions, ): Promise<{ url: URL; headers: { authorization?: string } }> => { const proxyTo = await parseProxyHeader(ctx, req) const defaultProxy = defaultService(ctx, req.path) @@ -121,8 +132,11 @@ export const createUrlAndHeaders = async ( const headers = requester ? (await ctx.serviceAuthHeaders(requester, aud)).headers : {} + const allowedHeaders = REQ_HEADERS_TO_FORWARD.concat( + options?.reqHeadersToForward ?? [], + ) // forward select headers to upstream services - for (const header of REQ_HEADERS_TO_FORWARD) { + for (const header of allowedHeaders) { const val = req.headers[header] if (val) { headers[header] = val