最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How do I upload to this google url - Stack Overflow

programmeradmin1浏览0评论

An API is returning to me this random google bucket url when trying to upload larger files to it:

/...-storage-bucket-prod/google-oauth2%.../...?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=blob-creator-reader%40tctn-eu-services-979d.iam.gserviceaccount%2...%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20241116T214909Z&X-Goog-Expires=59&X-Goog-Signature=...X-Goog-SignedHeaders=host%3Bx-goog-content-length-range%3Bx-goog-hash

I looked at trying to PUT to it, I even tried to give it host, x-goog-content-length-range, x-goog-hash for each chunk as I go through them, but it keeps returning the same error no matter what I do:

host:storage.googleapis
x-goog-content-length-range:0,16383
x-goog-hash:crc32c=ZVBtjQ==

host;x-goog-content-length-range;x-goog-hash
UNSIGNED-PAYLOAD</CanonicalRequest></Error>

My code:

def calculate_crc32c(data: bytes):
    return base64.b64encode(crc32c(data).to_bytes(4, 'big')).decode('utf-8')


def put_file(api: 'API', file: 'File', data: bytes):
    checksum_bs4 = calculate_crc32c(data)
    content_length = len(data)

    position = 0

    def file_chunk_generator(chunk_size=16384):
        nonlocal sync_event, data, content_length, position
        for i in range(0, len(data), chunk_size):
            chunk = data[i:i + chunk_size]
            yield chunk

    with httpx.Client(http2=False) as request:
        response = request.put(
            FILES_URL.format(api.document_storage_uri, file.hash),
            content=file_chunk_generator(),
            headers=(headers := {
                **api.session.headers,
                'content-length': str(content_length),
                'content-type': 'application/octet-stream',
                'x-goog-hash': f'crc32c={checksum_bs4}',
            })
        )

    if response.status_code == 302:
        position = 0
        print("Full google upload detected, continuing")
        url = response.headers.get("Location")
        print(url)
        with httpx.Client(http2=False) as request:

            for chunk in file_chunk_generator():
                print(f'{position},{position + len(chunk) - 1}')
                response = request.put(
                    url,
                    content=chunk,
                    headers={
                        'host': 'storage.googleapis',
                        'x-goog-content-length-range': f'{position},{(position + len(chunk) -1)}',
                        'x-goog-hash': f'crc32c={calculate_crc32c(chunk)}',
                        'Content-Length': str(len(chunk)),
                    }
                )
                if response.status_code != 200:
                    break
                else:
                    print("SUCCESS!!!")

    if response.status_code != 200:
        raise Exception(f"Put file failed - {response.status_code}\n{response.text}")
    else:
        print(file.uuid, "uploaded")

An API is returning to me this random google bucket url when trying to upload larger files to it:

https://storage.googleapis/...-storage-bucket-prod/google-oauth2%.../...?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=blob-creator-reader%40tctn-eu-services-979d.iam.gserviceaccount%2...%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20241116T214909Z&X-Goog-Expires=59&X-Goog-Signature=...X-Goog-SignedHeaders=host%3Bx-goog-content-length-range%3Bx-goog-hash

I looked at trying to PUT to it, I even tried to give it host, x-goog-content-length-range, x-goog-hash for each chunk as I go through them, but it keeps returning the same error no matter what I do:

host:storage.googleapis
x-goog-content-length-range:0,16383
x-goog-hash:crc32c=ZVBtjQ==

host;x-goog-content-length-range;x-goog-hash
UNSIGNED-PAYLOAD</CanonicalRequest></Error>

My code:

def calculate_crc32c(data: bytes):
    return base64.b64encode(crc32c(data).to_bytes(4, 'big')).decode('utf-8')


def put_file(api: 'API', file: 'File', data: bytes):
    checksum_bs4 = calculate_crc32c(data)
    content_length = len(data)

    position = 0

    def file_chunk_generator(chunk_size=16384):
        nonlocal sync_event, data, content_length, position
        for i in range(0, len(data), chunk_size):
            chunk = data[i:i + chunk_size]
            yield chunk

    with httpx.Client(http2=False) as request:
        response = request.put(
            FILES_URL.format(api.document_storage_uri, file.hash),
            content=file_chunk_generator(),
            headers=(headers := {
                **api.session.headers,
                'content-length': str(content_length),
                'content-type': 'application/octet-stream',
                'x-goog-hash': f'crc32c={checksum_bs4}',
            })
        )

    if response.status_code == 302:
        position = 0
        print("Full google upload detected, continuing")
        url = response.headers.get("Location")
        print(url)
        with httpx.Client(http2=False) as request:

            for chunk in file_chunk_generator():
                print(f'{position},{position + len(chunk) - 1}')
                response = request.put(
                    url,
                    content=chunk,
                    headers={
                        'host': 'storage.googleapis',
                        'x-goog-content-length-range': f'{position},{(position + len(chunk) -1)}',
                        'x-goog-hash': f'crc32c={calculate_crc32c(chunk)}',
                        'Content-Length': str(len(chunk)),
                    }
                )
                if response.status_code != 200:
                    break
                else:
                    print("SUCCESS!!!")

    if response.status_code != 200:
        raise Exception(f"Put file failed - {response.status_code}\n{response.text}")
    else:
        print(file.uuid, "uploaded")
Share Improve this question asked Nov 16, 2024 at 21:58 RedTTGRedTTG 547 bronze badges 4
  • It's a Google Signed URL. See using Signed URLs with resumable uploads – DazWilkin Commented Nov 16, 2024 at 22:13
  • @DazWilkin then why is it not happy with my headers? – RedTTG Commented Nov 16, 2024 at 23:23
  • You will want to POST to the Signed URL with Content-Type and Content-Length headers. If the service will accept resumable uploads, you'll be given a different URL to PUT chunks too. – DazWilkin Commented Nov 17, 2024 at 16:32
  • Your question is not a minimal repro and would benefit from including specific details of "the same error" and possibly the API that you're using that's generating the Signed URL. – DazWilkin Commented Nov 17, 2024 at 16:33
Add a comment  | 

1 Answer 1

Reset to default 0

The API was passing x-goog-content-length of 0,7GB that was the required header, not the chunk length

发布评论

评论列表(0)

  1. 暂无评论