Skip to content

Commit 7d17399

Browse files
authored
fix: use Azurite-compatible URL format for signed_upload_url (#216)
1 parent 89157c3 commit 7d17399

2 files changed

Lines changed: 71 additions & 1 deletion

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import type { ReadableStream } from 'node:stream/web'
2+
import { Buffer } from 'node:buffer'
3+
import { randomUUID } from 'node:crypto'
4+
5+
import { z } from 'zod'
6+
import { logger } from '~/lib/logger'
7+
8+
import { getStorage } from '~/lib/storage'
9+
10+
const pathParamsSchema = z.object({
11+
uploadId: z.coerce.number(),
12+
})
13+
14+
export default defineEventHandler(async (event) => {
15+
const parsedPathParams = pathParamsSchema.safeParse(event.context.params)
16+
if (!parsedPathParams.success)
17+
throw createError({
18+
statusCode: 400,
19+
statusMessage: `Invalid path parameters: ${parsedPathParams.error.message}`,
20+
})
21+
22+
if (getQuery(event).comp === 'blocklist') {
23+
setResponseStatus(event, 201)
24+
// prevent random EOF error with in tonistiigi/go-actions-cache caused by missing request id
25+
setHeader(event, 'x-ms-request-id', randomUUID())
26+
return
27+
}
28+
29+
const blockId = getQuery(event)?.blockid as string
30+
// if no block id, upload smaller than chunk size
31+
const chunkIndex = blockId ? getChunkIndexFromBlockId(blockId) : 0
32+
if (chunkIndex === undefined)
33+
throw createError({
34+
statusCode: 400,
35+
statusMessage: `Invalid block id: ${blockId}`,
36+
})
37+
38+
const { uploadId } = parsedPathParams.data
39+
40+
const stream = getRequestWebStream(event)
41+
if (!stream) {
42+
logger.debug('Upload: Request body is not a stream')
43+
throw createError({ statusCode: 400, statusMessage: 'Request body must be a stream' })
44+
}
45+
46+
const storage = await getStorage()
47+
await storage.uploadPart(uploadId, chunkIndex, stream as ReadableStream)
48+
49+
// prevent random EOF error with in tonistiigi/go-actions-cache caused by missing request id
50+
setHeader(event, 'x-ms-request-id', randomUUID())
51+
setResponseStatus(event, 201)
52+
})
53+
54+
function getChunkIndexFromBlockId(blockIdBase64: string) {
55+
const base64Decoded = Buffer.from(blockIdBase64, 'base64')
56+
57+
// 64 bytes used by docker buildx
58+
// 48 bytes used by everything else
59+
if (base64Decoded.length === 64) {
60+
return base64Decoded.readUInt32BE(16)
61+
} else if (base64Decoded.length === 48) {
62+
const decoded = base64Decoded.toString('utf8')
63+
64+
// slice off uuid and convert to number
65+
const index = Number.parseInt(decoded.slice(36))
66+
if (Number.isNaN(index)) return
67+
68+
return index
69+
}
70+
}

routes/twirp/github.actions.results.api.v1.CacheService/CreateCacheEntry.post.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ export default defineEventHandler(async (event) => {
3434

3535
return {
3636
ok: true,
37-
signed_upload_url: `${env.API_BASE_URL}/upload/${upload.id}`,
37+
signed_upload_url: `${env.API_BASE_URL}/devstoreaccount1/upload/${upload.id}`,
3838
}
3939
})

0 commit comments

Comments
 (0)