4

MSDN、WinInet がチャンク アップロードをサポートしていないと述べています (「クライアント コードはチャンクを実行する必要があります。」)。私にとっては、転送を手動でチャンクできることを意味していました。私の意図は、 HttpAddRequestHeadersを介して "Transfer-Encoding: chunked" を追加し、 HttpAddRequestHeaders HTTP_ADDREQ_FLAG_REPLACE を介して Content-Length を削除し、 InternetWriteFile ループでチャンク エンコード ブロックにデータを書き込むことでした。問題は、Content-Length を送信しないように WinInet を納得させることができないことです。削除した後でも、「Content-Length: 0」をサーバーに送信することになり (「Transfer-Encoding: chunked」に加えて)、サーバーを混乱させます。

また、 HSR_CHUNKED フラグをHttpSendRequestExに設定しようとしました。

WinInet に Content-Length の送信をスキップさせる例はありますか?

WinHTTP がチャンク アップロードをサポートしていると主張していることは知っていますが、WinInet には他の依存関係があるため、可能であればそこで問題を解決したいと考えています。

これが私が試したコードサンプルです:

#include <windows.h>
#include <wininet.h>
#include <tchar.h>
#include <stdio.h>

bool http_putfile(HINTERNET hConnection, TCHAR* resource);

#define HOST  _T("www.website.com")
#define RESOURCE _T("/path/for/resource")

int _tmain(int argc, TCHAR* argv[])
{
    LPCTSTR lpszHostName = HOST;
    INTERNET_PORT nServerPort = INTERNET_DEFAULT_HTTP_PORT;
    DWORD dwService = INTERNET_SERVICE_HTTP;
    DWORD dwFlags = NULL;
    DWORD dwContext = 0;

    HINTERNET hSession = InternetOpen(
        argv[0],
        INTERNET_OPEN_TYPE_DIRECT, 
        NULL,
        NULL,
        NULL);

    if(hSession != NULL)
    {
        HINTERNET hConnection = InternetConnect(
            hSession,
            lpszHostName,
            nServerPort,
            NULL,
            NULL,
            dwService,
            dwFlags,
            dwContext);

        if(hConnection != NULL)
        {
            http_putfile(hConnection, RESOURCE);

            InternetCloseHandle(hConnection);
        }
        else
        {
            printf("InternetConnect failed: %d\n", GetLastError());
        }

        InternetCloseHandle(hSession);
    }
    else
    {
        printf("InternetOpen failed: %d\n", GetLastError());
    }

    return 0;
}

bool http_putfile(HINTERNET hConnection, TCHAR* resource)
{
    bool result = false;

    HINTERNET hRequest = HttpOpenRequest(
        hConnection,
        _T("PUT"),
        resource,
        NULL,
        NULL,
        NULL,
        INTERNET_FLAG_RELOAD | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_CACHE_WRITE,
        0);

    if(hRequest != NULL)
    {
        HttpAddRequestHeaders(
            hRequest,
            _T("Transfer-Encoding: chunked\r\n"),
            -1L,
            HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);

        // have tried:
        // Content-Length
        // Content-Length:
        // Content-Length\r\n
        // Content-Length:\r\n
        // all with/without HTTP_ADDREQ_FLAG_ADD.  Have even tried adding in a Content-Length
        // and then removing it.  All results show "Content-Length: 0" in the header on the wire.
        if(HttpAddRequestHeaders(
            hRequest,
            _T("Content-Length"),
            -1L,
            HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE) == FALSE)
        {
            DWORD err = GetLastError();
        }

        // have tried both 0 here for flags as documented on msdn
        // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384318%28v=vs.85%29.aspx
        // as well as other combinations of INITIATE/CHUNKED
        if(HttpSendRequestEx(hRequest, NULL, NULL, HSR_INITIATE | HSR_CHUNKED /* 0 */, NULL))
        {
            DWORD wrote = 0;
            char* chunks = "5\r\nCHUNK0\r\n";

            if(InternetWriteFile(
                    hRequest,
                    chunks,
                    strlen(chunks),
                    &wrote) == FALSE)
            {
                printf("InternetWriteFile failed: %d\n", GetLastError());
            }

            HttpEndRequest(hRequest, NULL, 0, NULL);
        }
        else
        {
            printf("HttpSendRequestEx failed: %d\n", GetLastError);
        }

        InternetCloseHandle(hRequest);
    }
    else
    {
        printf("HttpOpenRequest failed: %d\n", GetLastError());
    }

    return result;
}
4

2 に答える 2

0

素晴らしい質問です。私はこれに何時間もイライラしていました。

あなたの本能はHTTP_ADDREQ_FLAG_REPLACE正しかったことが判明しました.. 具体的には、ステータス コールバックを登録する必要があります。コールバックが で呼び出されたときINTERNET_STATUS_CONNECTED_TO_SERVERつまりヘッダーを削除したときです。

// Inside InternetStatusCallback
//
if (dwInternetStatus == INTERNET_STATUS_CONNECTED_TO_SERVER)
{
  HttpAddRequestHeaders(Handle, L"Content-Length", -1, HTTP_ADDREQ_FLAG_REPLACE);
}
于 2013-10-17T05:27:51.283 に答える
0

まあ、あなたは正しいようです。実際、WinINet がチャンク アップロードをサポートしていることを示すものは何もありません。WinHTTP のみが行います。Wine のソース コード(かなり正確である傾向があります) を見ると、「Content-Length」ヘッダーは常に「GET」以外のメソッドのリクエストに追加されます。

HTTP 仕様によると、ID 以外の「Transfer-Encoding」ヘッダーが存在する場合、メッセージはチャンクされていると見なされます。「Content-Length」ヘッダーも存在する場合は、無視する必要があります。偽の「Content-Length: 0」ヘッダーが問題を引き起こしている場合は、サーバーの問題であると主張できます。WinHTTP を試してみて、問題が解決するかどうかを確認します。

于 2012-04-09T20:36:44.873 に答える