C++ HTTP#u RECEIVE#u REQUEST#u FLAG#u FLUSH#u BODY不';复制http正文

C++ HTTP#u RECEIVE#u REQUEST#u FLAG#u FLUSH#u BODY不';复制http正文,c++,windows,http,httpserver,simplehttpserver,C++,Windows,Http,Httpserver,Simplehttpserver,根据,传递到HttpReceiveHttpRequest函数中的HTTP\u RECEIVE\u REQUEST\u FLAG\u FLUSH\u BODY标志会导致将实体体复制到传入的HTTP\u REQUEST结构中 我编写了一个简单的http服务器(见下文),它使用此标志集调用此函数。然后,我从一个测试客户机发送了一个4MBPOST请求,并将一个调试器连接到http服务器,以查看函数返回后有多少字节被复制到http_请求结构中;我注意到这并没有复制http主体,只是复制了头 有没有办法让H

根据,传递到
HttpReceiveHttpRequest
函数中的
HTTP\u RECEIVE\u REQUEST\u FLAG\u FLUSH\u BODY
标志会导致将实体体复制到传入的
HTTP\u REQUEST
结构中

我编写了一个简单的http服务器(见下文),它使用此标志集调用此函数。然后,我从一个测试客户机发送了一个4MB
POST
请求,并将一个调试器连接到http服务器,以查看函数返回后有多少字节被复制到
http_请求
结构中;我注意到这并没有复制http主体,只是复制了头

有没有办法让
HttpReceiveHttpRequest
将整个4MB正文复制到HTTP请求的
pEntityChunks
部分

注意:当设置了
HTTP\u RECEIVE\u REQUEST\u ENTITY\u body\u FILL\u BUFFER
标志时,我验证了
HttpReceiveRequestEntityBody
函数是否复制了整个正文

HTTP服务器

// HttpServer.cpp : Defines the entry point for the console application.
//

#ifndef UNICODE
#define UNICODE
#endif

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <http.h>
#include <stdio.h>
#include <string>
#include <memory>

#pragma comment(lib, "httpapi.lib")

int RequestBufferLength = 4194304 + 4096;
int ResponseBufferLength = 4194304;
int SmallBufferLength = 100;

std::unique_ptr<char[]> ResponseBuffer = std::make_unique<char[]>(ResponseBufferLength);
std::unique_ptr<char[]> SmallBuffer = std::make_unique<char[]>(SmallBufferLength);
std::unique_ptr<char[]> RequestBuffer = std::make_unique<char[]>(RequestBufferLength);

DWORD SendHttpResponse(HANDLE hReqQueue, PHTTP_REQUEST pRequest)
{
    HTTP_RESPONSE response;
    HTTP_DATA_CHUNK dataChunk;
    DWORD result;
    DWORD bytesSent;

    // Initialize the HTTP response structure.
    RtlZeroMemory(&response, sizeof(response));
    response.StatusCode = 200;                      
    response.pReason = "OK";                         
    response.ReasonLength = 2;

    // Add known headers.
    std::string contentType = "text/html";
    response.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = contentType.c_str();
    response.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)contentType.length();

    // Add the body
    if (pRequest->Verb == HttpVerbGET)
    {
        // Send big response
        dataChunk.DataChunkType = HttpDataChunkFromMemory;
        dataChunk.FromMemory.pBuffer = ResponseBuffer.get();
        dataChunk.FromMemory.BufferLength = ResponseBufferLength;
    }
    else
    {
        // Send small response
        dataChunk.DataChunkType = HttpDataChunkFromMemory;
        dataChunk.FromMemory.pBuffer = SmallBuffer.get();
        dataChunk.FromMemory.BufferLength = SmallBufferLength;
    }

    response.EntityChunkCount = 1;
    response.pEntityChunks = &dataChunk;

    // Because the entity body is sent in one call, it is not
    // required to specify the Content-Length.
    result = HttpSendHttpResponse(
        hReqQueue,           // ReqQueueHandle
        pRequest->RequestId, // Request ID
        0,                   // Flags
        &response,           // HTTP response
        NULL,                // HTTP Cache Policy
        &bytesSent,          // bytes sent  (OPTIONAL)
        NULL,                // pReserved2  (must be NULL)
        0,                   // Reserved3   (must be 0)
        NULL,                // LPOVERLAPPED(OPTIONAL)
        NULL                 // pReserved4  (must be NULL)
        );

    if (result != NO_ERROR)
    {
        wprintf(L"HttpSendHttpResponse failed with %lu \n", result);
    }

    return result;
}

DWORD ReceiveRequests(HANDLE hReqQueue)
{
    ULONG result;
    HTTP_REQUEST_ID requestId;
    DWORD bytesRead;
    PHTTP_REQUEST pRequest;

    pRequest = (PHTTP_REQUEST)RequestBuffer.get();

    // Wait for a new request. This is indicated by a NULL 
    // request ID.
    HTTP_SET_NULL_ID(&requestId);

    for (;;)
    {
        result = HttpReceiveHttpRequest(
            hReqQueue,
            requestId,
            HTTP_RECEIVE_REQUEST_FLAG_FLUSH_BODY,
            pRequest,
            RequestBufferLength,
            &bytesRead,
            NULL);

        if (NO_ERROR == result)
        {
            switch (pRequest->Verb)
            {
            case HttpVerbGET:
                result = SendHttpResponse(hReqQueue, pRequest);
                break;
            case HttpVerbPUT:
            case HttpVerbPOST:
                result = HttpReceiveRequestEntityBody(
                    hReqQueue,
                    pRequest->RequestId,
                    HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER,
                    RequestBuffer.get() + bytesRead,
                    RequestBufferLength - bytesRead,
                    &bytesRead,
                    NULL);

                if (NO_ERROR == result)
                {
                    result = SendHttpResponse(hReqQueue, pRequest);
                }
                break;
            default:
                wprintf(L"Got a unknown request for %ws \n", pRequest->CookedUrl.pFullUrl);
                result = E_FAIL;
                break;
            }

            if (result != NO_ERROR)
            {
                break;
            }

            // Reset the Request ID to handle the next request.
            HTTP_SET_NULL_ID(&requestId);
        }
        else
        {
            break;
        }
    }

    return result;
}

int main(int argc, char** argv)
{
    std::wstring url;
    if (argc == 1)
    {
        url = L"http://127.0.0.1:80/NativeBigDataTest";
    }
    else
    {
        std::string serverIp(argv[1]);
        url = L"http://" + std::wstring(serverIp.begin(), serverIp.end()) + L":80/NativeBigDataTest";
    }    

    HTTP_SERVER_SESSION_ID session;
    HTTP_URL_GROUP_ID urlGroup;
    HANDLE hReqQueue = NULL;
    HTTP_BINDING_INFO bindingInfo;
    ULONG retCode;

    // Initialize HTTP Server APIs
    retCode = HttpInitialize(
                    HTTPAPI_VERSION_2,
                    HTTP_INITIALIZE_SERVER,    // Flags
                    NULL                       // Reserved
                    );
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpInitialize failed with %lu \n", retCode);
        return retCode;
    }

    // Create server session    
    retCode = HttpCreateServerSession(HTTPAPI_VERSION_2, &session, 0);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpCreateServerSession failed with %lu \n", retCode);
        goto CleanUp5;
    }

    // Create Url Group    
    retCode = HttpCreateUrlGroup(session, &urlGroup, 0);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpCreateUrlGroup failed with %lu \n", retCode);
        goto CleanUp4;
    }

    // Add url to group
    retCode = HttpAddUrlToUrlGroup(urlGroup, url.c_str(), HTTP_URL_CONTEXT{}, 0);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpAddUrlToUrlGroup failed with %lu \n", retCode);
        goto CleanUp3;
    }

    // Create a Request Queue Handle    
    retCode = HttpCreateRequestQueue(HTTPAPI_VERSION_2, NULL, NULL, 0, &hReqQueue);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpCreateHttpHandle failed with %lu \n", retCode);
        goto CleanUp2;
    }

    // Bind request queue to url group    
    bindingInfo.RequestQueueHandle = hReqQueue;
    bindingInfo.Flags.Present = 1;
    retCode = HttpSetUrlGroupProperty(urlGroup, HttpServerBindingProperty, &bindingInfo, sizeof(bindingInfo));
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpSetUrlGroupProperty failed with %lu \n", retCode);
        goto CleanUp1;
    }

    wprintf(L"Listening on url %s\n", url.c_str());

    // Receive requests
    ReceiveRequests(hReqQueue);

CleanUp1:
    // Close the Request Queue handle.
    retCode = HttpCloseRequestQueue(hReqQueue);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpCloseRequestQueue failed with %lu \n", retCode);
    }

CleanUp2:
    // Call HttpRemoveUrlFromUrlGroup for all added URLs.
    retCode = HttpRemoveUrlFromUrlGroup(
        urlGroup,
        url.c_str(),
        0);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpRemoveUrlFromUrlGroup failed with %lu \n", retCode);
    }

CleanUp3:
    // Close Url group
    retCode = HttpCloseUrlGroup(urlGroup);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpCloseUrlGroup failed with %lu \n", retCode);
    }

CleanUp4:
    // Close Session
    retCode = HttpCloseServerSession(session);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpCloseServerSession failed with %lu \n", retCode);
    }

CleanUp5:
    // Call HttpTerminate.
    retCode = HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);
    if (retCode != NO_ERROR)
    {
        wprintf(L"HttpTerminate failed with %lu \n", retCode);
    }

    return retCode;
}
//HttpServer.cpp:定义控制台应用程序的入口点。
//
#ifndef UNICODE
#定义UNICODE
#恩迪夫
#ifndef\u WIN32\u WINNT
#定义_WIN32_WINNT 0x0600
#恩迪夫
#如果NDEF WIN32_LEAN_和_MEAN
#定义WIN32_精益_和_平均值
#恩迪夫
#包括
#包括
#包括
#包括
#包括
#pragma注释(lib,“httpapi.lib”)
int RequestBufferLength=4194304+4096;
int ResponseBufferLength=4194304;
int SmallBufferLength=100;
std::unique_ptr ResponseBuffer=std::make_unique(ResponseBufferLength);
std::unique_ptr SmallBuffer=std::make_unique(SmallBufferLength);
std::unique_ptr RequestBuffer=std::make_unique(RequestBufferLength);
DWORD SendHttpResponse(处理hReqQueue、PHTTP_请求预请求)
{
HTTP_响应;
HTTP_DATA_CHUNK dataChunk;
德沃德结果;
德沃德·拜特森特;
//初始化HTTP响应结构。
RtlZeroMemory(&response,sizeof(response));
response.StatusCode=200;
response.pReason=“OK”;
响应长度=2;
//添加已知的标题。
std::string contentType=“text/html”;
response.Headers.KnownHeaders[HttpHeaderContentType].pRawValue=contentType.c_str();
response.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength=(USHORT)contentType.length();
//添加主体
if(pRequest->Verb==HttpVerbGET)
{
//作出重大回应
dataChunk.DataChunkType=HttpDataChunkFromMemory;
dataChunk.FromMemory.pBuffer=ResponseBuffer.get();
dataChunk.FromMemory.BufferLength=响应缓冲长度;
}
其他的
{
//发送小响应
dataChunk.DataChunkType=HttpDataChunkFromMemory;
dataChunk.FromMemory.pBuffer=SmallBuffer.get();
dataChunk.FromMemory.BufferLength=SmallBufferLength;
}
response.EntityChunkCount=1;
response.pEntityChunks=&dataChunk;
//因为实体主体是在一次调用中发送的,所以它不是
//需要指定内容长度。
结果=HttpSendHttpResponse(
hReqQueue,//ReqQueueHandle
pRequest->RequestId,//请求ID
0,//标志
&response,//HTTP响应
NULL,//HTTP缓存策略
&bytesSent,//已发送字节(可选)
NULL,//pReserved2(必须为NULL)
0,//Reserved3(必须为0)
NULL,//LPOVERLAPPED(可选)
NULL//pReserved4(必须为NULL)
);
如果(结果!=无错误)
{
wprintf(L“HttpSendHttpResponse失败,返回%lu\n”,结果);
}
返回结果;
}
DWORD接收请求(处理hReqQueue)
{
乌龙结果;
HTTP_请求_ID requestId;
德沃德·拜特斯雷德;
PHTTP_请求预先请求;
pRequest=(PHTTP_请求)RequestBuffer.get();
//等待新请求。这由NULL指示
//请求ID。
HTTP\u SET\u NULL\u ID(&requestId);
对于(;;)
{
结果=HttpReceiveHttpRequest(
hReqQueue,
请求ID,
HTTP\u接收\u请求\u标志\u刷新\u正文,
预谋,
请求缓冲长度,
&拜特斯拉德,
无效);
如果(无错误==结果)
{
切换(任务前->动词)
{
案例HttpVerbGET:
结果=SendHttpResponse(hReqQueue,pRequest);
打破
案例HttpVerbPUT:
案例HttpVerbPOST:
结果=HttpReceiveRequestEntityBody(
hReqQueue,
pRequest->RequestId,
HTTP\u接收\u请求\u实体\u主体\u标志\u填充\u缓冲区,
RequestBuffer.get()+字节读取,
RequestBufferLength-字节读取,
&拜特斯拉德,
无效);
如果(无错误==结果)
{
结果=SendHttpResponse(hReqQueue,pRequest);
}
打破
违约:
wprintf(L“获取了%ws的未知请求\n”,pRequest->CookedUrl.pFullUrl);
结果=E_失败;
打破
}
如果(结果!=无错误)
{
打破
}
//重置请求ID以处理下一个请求。
HTTP\u SET\u NULL\u ID(&requestId);
}
其他的
{
打破
}
}
返回结果;
}
int main(int argc,字符**argv)
{
std::wstring url;
如果(argc==1)
{
url=L“http://127.0.0.1:80/NativeBigDataTest";
}
其他的
{
std::string serverIp(argv[1]);
url=L“http://”+std::wstring(serverIp.begin(),serverIp.end())+L:80/NativeBigDataTest”;
}    
HTTP_服务器_会话_ID会话;
HTTP\u URL\u GROUP\u ID urlGroup;
句柄hReqQueue=NULL;
HTT