HTTP 服务器示例应用程序

05/31/2018

本文内容

下面的示例应用程序演示如何使用 HTTP 服务器 API 来执行服务器端任务。 第一个示例中包含的 "precomp" 文件包括运行示例所需的所有标头,例如:

#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

#include

#include

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

Main 和初步

#include "precomp.h"

//

// Macros.

//

#define INITIALIZE_HTTP_RESPONSE( resp, status, reason ) \

do \

{ \

RtlZeroMemory( (resp), sizeof(*(resp)) ); \

(resp)->StatusCode = (status); \

(resp)->pReason = (reason); \

(resp)->ReasonLength = (USHORT) strlen(reason); \

} while (FALSE)

#define ADD_KNOWN_HEADER(Response, HeaderId, RawValue) \

do \

{ \

(Response).Headers.KnownHeaders[(HeaderId)].pRawValue = \

(RawValue);\

(Response).Headers.KnownHeaders[(HeaderId)].RawValueLength = \

(USHORT) strlen(RawValue); \

} while(FALSE)

#define ALLOC_MEM(cb) HeapAlloc(GetProcessHeap(), 0, (cb))

#define FREE_MEM(ptr) HeapFree(GetProcessHeap(), 0, (ptr))

//

// Prototypes.

//

DWORD DoReceiveRequests(HANDLE hReqQueue);

DWORD

SendHttpResponse(

IN HANDLE hReqQueue,

IN PHTTP_REQUEST pRequest,

IN USHORT StatusCode,

IN PSTR pReason,

IN PSTR pEntity

);

DWORD

SendHttpPostResponse(

IN HANDLE hReqQueue,

IN PHTTP_REQUEST pRequest

);

/*******************************************************************++

Routine Description:

main routine

Arguments:

argc - # of command line arguments.

argv - Arguments.

Return Value:

Success/Failure

--*******************************************************************/

int __cdecl wmain(

int argc,

wchar_t * argv[]

)

{

ULONG retCode;

HANDLE hReqQueue = NULL;

int UrlAdded = 0;

HTTPAPI_VERSION HttpApiVersion = HTTPAPI_VERSION_1;

if (argc < 2)

{

wprintf(L"%ws: [Url2] ... \n", argv[0]);

return -1;

}

初始化 HTTP 服务

//

// Initialize HTTP Server APIs

//

retCode = HttpInitialize(

HttpApiVersion,

HTTP_INITIALIZE_SERVER, // Flags

NULL // Reserved

);

if (retCode != NO_ERROR)

{

wprintf(L"HttpInitialize failed with %lu \n", retCode);

return retCode;

}

//

// Create a Request Queue Handle

//

retCode = HttpCreateHttpHandle(

&hReqQueue, // Req Queue

0 // Reserved

);

if (retCode != NO_ERROR)

{

wprintf(L"HttpCreateHttpHandle failed with %lu \n", retCode);

goto CleanUp;

}

注册要侦听的 Url

//

// The command line arguments represent URIs that to

// listen on. Call HttpAddUrl for each URI.

//

// The URI is a fully qualified URI and must include the

// terminating (/) character.

//

for (int i = 1; i < argc; i++)

{

wprintf(L"listening for requests on the following url: %s\n", argv[i]);

retCode = HttpAddUrl(

hReqQueue, // Req Queue

argv[i], // Fully qualified URL

NULL // Reserved

);

if (retCode != NO_ERROR)

{

wprintf(L"HttpAddUrl failed with %lu \n", retCode);

goto CleanUp;

}

else

{

//

// Track the currently added URLs.

//

UrlAdded ++;

}

}

调用例程以接收请求

DoReceiveRequests(hReqQueue);

清除 HTTP 服务器 API

CleanUp:

//

// Call HttpRemoveUrl for all added URLs.

//

for(int i=1; i<=UrlAdded; i++)

{

HttpRemoveUrl(

hReqQueue, // Req Queue

argv[i] // Fully qualified URL

);

}

//

// Close the Request Queue handle.

//

if(hReqQueue)

{

CloseHandle(hReqQueue);

}

//

// Call HttpTerminate.

//

HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);

return retCode;

接收请求

/*******************************************************************++

Routine Description:

The function to receive a request. This function calls the

corresponding function to handle the response.

Arguments:

hReqQueue - Handle to the request queue

Return Value:

Success/Failure.

--*******************************************************************/

DWORD DoReceiveRequests(

IN HANDLE hReqQueue

)

{

ULONG result;

HTTP_REQUEST_ID requestId;

DWORD bytesRead;

PHTTP_REQUEST pRequest;

PCHAR pRequestBuffer;

ULONG RequestBufferLength;

//

// Allocate a 2 KB buffer. This size should work for most

// requests. The buffer size can be increased if required. Space

// is also required for an HTTP_REQUEST structure.

//

RequestBufferLength = sizeof(HTTP_REQUEST) + 2048;

pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength );

if (pRequestBuffer == NULL)

{

return ERROR_NOT_ENOUGH_MEMORY;

}

pRequest = (PHTTP_REQUEST)pRequestBuffer;

//

// Wait for a new request. This is indicated by a NULL

// request ID.

//

HTTP_SET_NULL_ID( &requestId );

for(;;)

{

RtlZeroMemory(pRequest, RequestBufferLength);

result = HttpReceiveHttpRequest(

hReqQueue, // Req Queue

requestId, // Req ID

0, // Flags

pRequest, // HTTP request buffer

RequestBufferLength,// req buffer length

&bytesRead, // bytes received

NULL // LPOVERLAPPED

);

处理 HTTP 请求

if(NO_ERROR == result)

{

//

// Worked!

//

switch(pRequest->Verb)

{

case HttpVerbGET:

wprintf(L"Got a GET request for %ws \n",

pRequest->CookedUrl.pFullUrl);

result = SendHttpResponse(

hReqQueue,

pRequest,

200,

"OK",

"Hey! You hit the server \r\n"

);

break;

case HttpVerbPOST:

wprintf(L"Got a POST request for %ws \n",

pRequest->CookedUrl.pFullUrl);

result= SendHttpPostResponse(hReqQueue, pRequest);

break;

default:

wprintf(L"Got a unknown request for %ws \n",

pRequest->CookedUrl.pFullUrl);

result = SendHttpResponse(

hReqQueue,

pRequest,

503,

"Not Implemented",

NULL

);

break;

}

if(result != NO_ERROR)

{

break;

}

//

// Reset the Request ID to handle the next request.

//

HTTP_SET_NULL_ID( &requestId );

}

else if(result == ERROR_MORE_DATA)

{

//

// The input buffer was too small to hold the request

// headers. Increase the buffer size and call the

// API again.

//

// When calling the API again, handle the request

// that failed by passing a RequestID.

//

// This RequestID is read from the old buffer.

//

requestId = pRequest->RequestId;

//

// Free the old buffer and allocate a new buffer.

//

RequestBufferLength = bytesRead;

FREE_MEM( pRequestBuffer );

pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength );

if (pRequestBuffer == NULL)

{

result = ERROR_NOT_ENOUGH_MEMORY;

break;

}

pRequest = (PHTTP_REQUEST)pRequestBuffer;

}

else if(ERROR_CONNECTION_INVALID == result &&

!HTTP_IS_NULL_ID(&requestId))

{

// The TCP connection was corrupted by the peer when

// attempting to handle a request with more buffer.

// Continue to the next request.

HTTP_SET_NULL_ID( &requestId );

}

else

{

break;

}

}

if(pRequestBuffer)

{

FREE_MEM( pRequestBuffer );

}

return result;

}

发送 HTTP 响应

/*******************************************************************++

Routine Description:

The routine sends a HTTP response

Arguments:

hReqQueue - Handle to the request queue

pRequest - The parsed HTTP request

StatusCode - Response Status Code

pReason - Response reason phrase

pEntityString - Response entity body

Return Value:

Success/Failure.

--*******************************************************************/

DWORD SendHttpResponse(

IN HANDLE hReqQueue,

IN PHTTP_REQUEST pRequest,

IN USHORT StatusCode,

IN PSTR pReason,

IN PSTR pEntityString

)

{

HTTP_RESPONSE response;

HTTP_DATA_CHUNK dataChunk;

DWORD result;

DWORD bytesSent;

//

// Initialize the HTTP response structure.

//

INITIALIZE_HTTP_RESPONSE(&response, StatusCode, pReason);

//

// Add a known header.

//

ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/html");

if(pEntityString)

{

//

// Add an entity chunk.

//

dataChunk.DataChunkType = HttpDataChunkFromMemory;

dataChunk.FromMemory.pBuffer = pEntityString;

dataChunk.FromMemory.BufferLength =

(ULONG) strlen(pEntityString);

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, // pReserved1

&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;

}

发送 HTTP POST 响应

#define MAX_ULONG_STR ((ULONG) sizeof("4294967295"))

/*******************************************************************++

Routine Description:

The routine sends a HTTP response after reading the entity body.

Arguments:

hReqQueue - Handle to the request queue.

pRequest - The parsed HTTP request.

Return Value:

Success/Failure.

--*******************************************************************/

DWORD SendHttpPostResponse(

IN HANDLE hReqQueue,

IN PHTTP_REQUEST pRequest

)

{

HTTP_RESPONSE response;

DWORD result;

DWORD bytesSent;

PUCHAR pEntityBuffer;

ULONG EntityBufferLength;

ULONG BytesRead;

ULONG TempFileBytesWritten;

HANDLE hTempFile;

TCHAR szTempName[MAX_PATH + 1];

CHAR szContentLength[MAX_ULONG_STR];

HTTP_DATA_CHUNK dataChunk;

ULONG TotalBytesRead = 0;

BytesRead = 0;

hTempFile = INVALID_HANDLE_VALUE;

//

// Allocate space for an entity buffer. Buffer can be increased

// on demand.

//

EntityBufferLength = 2048;

pEntityBuffer = (PUCHAR) ALLOC_MEM( EntityBufferLength );

if (pEntityBuffer == NULL)

{

result = ERROR_NOT_ENOUGH_MEMORY;

wprintf(L"Insufficient resources \n");

goto Done;

}

//

// Initialize the HTTP response structure.

//

INITIALIZE_HTTP_RESPONSE(&response, 200, "OK");

//

// For POST, echo back the entity from the

// client

//

// NOTE: If the HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY flag had been

// passed with HttpReceiveHttpRequest(), the entity would

// have been a part of HTTP_REQUEST (using the pEntityChunks

// field). Because that flag was not passed, there are no

// o entity bodies in HTTP_REQUEST.

//

if(pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS)

{

// The entity body is sent over multiple calls. Collect

// these in a file and send back. Create a temporary

// file.

//

if(GetTempFileName(

L".",

L"New",

0,

szTempName

) == 0)

{

result = GetLastError();

wprintf(L"GetTempFileName failed with %lu \n", result);

goto Done;

}

hTempFile = CreateFile(

szTempName,

GENERIC_READ | GENERIC_WRITE,

0, // Do not share.

NULL, // No security descriptor.

CREATE_ALWAYS, // Overrwrite existing.

FILE_ATTRIBUTE_NORMAL, // Normal file.

NULL

);

if(hTempFile == INVALID_HANDLE_VALUE)

{

result = GetLastError();

wprintf(L"Cannot create temporary file. Error %lu \n",

result);

goto Done;

}

do

{

//

// Read the entity chunk from the request.

//

BytesRead = 0;

result = HttpReceiveRequestEntityBody(

hReqQueue,

pRequest->RequestId,

0,

pEntityBuffer,

EntityBufferLength,

&BytesRead,

NULL

);

switch(result)

{

case NO_ERROR:

if(BytesRead != 0)

{

TotalBytesRead += BytesRead;

WriteFile(

hTempFile,

pEntityBuffer,

BytesRead,

&TempFileBytesWritten,

NULL

);

}

break;

case ERROR_HANDLE_EOF:

//

// The last request entity body has been read.

// Send back a response.

//

// To illustrate entity sends via

// HttpSendResponseEntityBody, the response will

// be sent over multiple calls. To do this,

// pass the HTTP_SEND_RESPONSE_FLAG_MORE_DATA

// flag.

if(BytesRead != 0)

{

TotalBytesRead += BytesRead;

WriteFile(

hTempFile,

pEntityBuffer,

BytesRead,

&TempFileBytesWritten,

NULL

);

}

//

// Because the response is sent over multiple

// API calls, add a content-length.

//

// Alternatively, the response could have been

// sent using chunked transfer encoding, by

// passimg "Transfer-Encoding: Chunked".

//

// NOTE: Because the TotalBytesread in a ULONG

// are accumulated, this will not work

// for entity bodies larger than 4 GB.

// For support of large entity bodies,

// use a ULONGLONG.

//

sprintf_s(szContentLength, MAX_ULONG_STR, "%lu", TotalBytesRead);

ADD_KNOWN_HEADER(

response,

HttpHeaderContentLength,

szContentLength

);

result =

HttpSendHttpResponse(

hReqQueue, // ReqQueueHandle

pRequest->RequestId, // Request ID

HTTP_SEND_RESPONSE_FLAG_MORE_DATA,

&response, // HTTP response

NULL, // pReserved1

&bytesSent, // bytes sent-optional

NULL, // pReserved2

0, // Reserved3

NULL, // LPOVERLAPPED

NULL // pReserved4

);

if(result != NO_ERROR)

{

wprintf(

L"HttpSendHttpResponse failed with %lu \n",

result

);

goto Done;

}

//

// Send entity body from a file handle.

//

dataChunk.DataChunkType =

HttpDataChunkFromFileHandle;

dataChunk.FromFileHandle.

ByteRange.StartingOffset.QuadPart = 0;

dataChunk.FromFileHandle.

ByteRange.Length.QuadPart =

HTTP_BYTE_RANGE_TO_EOF;

dataChunk.FromFileHandle.FileHandle = hTempFile;

result = HttpSendResponseEntityBody(

hReqQueue,

pRequest->RequestId,

0, // This is the last send.

1, // Entity Chunk Count.

&dataChunk,

NULL,

NULL,

0,

NULL,

NULL

);

if(result != NO_ERROR)

{

wprintf(

L"HttpSendResponseEntityBody failed %lu\n",

result

);

}

goto Done;

break;

default:

wprintf(

L"HttpReceiveRequestEntityBody failed with %lu \n",

result);

goto Done;

}

} while(TRUE);

}

else

{

// This request does not have an entity body.

//

result = HttpSendHttpResponse(

hReqQueue, // ReqQueueHandle

pRequest->RequestId, // Request ID

0,

&response, // HTTP response

NULL, // pReserved1

&bytesSent, // bytes sent (optional)

NULL, // pReserved2

0, // Reserved3

NULL, // LPOVERLAPPED

NULL // pReserved4

);

if(result != NO_ERROR)

{

wprintf(L"HttpSendHttpResponse failed with %lu \n",

result);

}

}

Done:

if(pEntityBuffer)

{

FREE_MEM(pEntityBuffer);

}

if(INVALID_HANDLE_VALUE != hTempFile)

{

CloseHandle(hTempFile);

DeleteFile(szTempName);

}

return result;

}

微软服务器应用软件,HTTP 服务器示例应用程序相关推荐

  1. WEB服务器、应用程序服务器、HTTP服务器区别(基础普及)

    一 常见的WEB服务器和应用服务器 在UNIX和LINUX平台下使用最广泛的免费web服务器是W3C.NCSA和APACHE服务器,而Windows平台NT/2000/2003使用IIS的WEB服务器 ...

  2. 应用程序服务器和Web服务器之间有什么区别?

    应用程序服务器和Web服务器之间有什么区别? #1楼 最大的不同是Web服务器处理HTTP请求,而应用程序服务器将在任意数量的协议上执行业务逻辑. #2楼 这取决于特定的体系结构. 某些应用程序服务器 ...

  3. 【原】Sharepoint安装:此服务器不是该搜索应用程序的索引器

    装Sharepoint,遇到诡异问题: 启动"Windows SharePoint Services 搜索"时,报错:此服务器不是该搜索应用程序的索引器. 在网上四处寻访,有说权限 ...

  4. WEB服务器、应用程序服务器、HTTP服务器的区别

    WEB服务器.应用程序服务器.HTTP服务器的区别 Web服务器: 基本功能就是提供Web信息浏览服务.它只需支持HTTP协议.HTML文档格式及URL.与客户端的网络浏览器配合.因为Web服务器主要 ...

  5. WEB服务器和HTTP服务器和应用服务器的区别?(web服务器就是HTTP服务器)为什么要把Web服务器独立配置,和应用程序服务器一前一后?

    参考文章1:WEB服务器.应用程序服务器.HTTP服务器区别 参考文章2:如何区分Web服务器.HTTP服务器.应用程序服务器 WEB服务器.应用程序服务器.HTTP服务器有何区别?IIS.Apach ...

  6. vivado在远程服务器上完成本地设备的程序烧写和调试(vivado远程调试)

    vivado远程调试 目录 1 概述 2 本地设置 3 远程服务器设置 1 概述 本文用于描述FPGA开发过程中,使用远程服务器时,直接在远程服务器连接到本地设备进行程序的烧写和调试的过程. 即运用场 ...

  7. 微软DNS服务器默认,DNS 服务器成为一座岛 - Windows Server | Microsoft Docs

    当域控制器指向 DNS 服务器自身时,DNS 服务器将成为一座_msdcs.ForestDnsName 域 10/19/2020 本文内容 本文提供了一种解决方案,解决当域控制器指向 DNS 服务器自 ...

  8. 您试图在此 Web 服务器上访问的 Web 应用程序当前不可用。

    您试图在此 Web 服务器上访问的 Web 应用程序当前不可用.请点击 Web 浏览器中的"刷新"按钮重试您的请求.管理员注意事项: 详述此特定请求失败原因的错误信息可在 Web ...

  9. 一个服务器可以放几个小程序,一个服务器可以放几个小程序

    一个服务器可以放几个小程序 内容精选 换一换 有很多网站,特别是目前的程序比较快,很多网站管理员可以使用不同的程序来构建网站,比如当下比较流行的PHP建站程序,当然还有之前比较火的APS,.net网站 ...

最新文章

  1. 互联网大脑如何产生“梦境“并形成元宇宙
  2. Android点击事件(click button)的四种写法
  3. 【Ping】unix - ping命令的退出状态
  4. Go 类型别名与类型声明的区别
  5. 弹框位置设置html,JQuery弹出框定位实现方法
  6. python中的位置怎么看_如何知道项目在Python有序字典中的位置
  7. tableau使用_使用Tableau探索墨尔本房地产市场
  8. 是否有任何python库可以从自然语言中解析日期和时间?
  9. Proxy动态代理代码示例
  10. 数组使用方法集合(建议收藏)
  11. aarch64 arm上交叉编译mysql-2.7.35
  12. python与vb可以互换吗_VB转换为Python:在线把VB代码转为Python
  13. Visual Studio 2019 Community 离线注册教程
  14. Drools4.0官方使用手册中文
  15. 直流电机单闭环调速matlab仿真,单闭环直流电机调速Simulink仿真.docx
  16. C#毕业设计——基于C#+asp.net+ACCESS的电子商务网站设计与实现(毕业论文+程序源码)——电子商务网站
  17. matlab中eval函数保存图片,Matlab中eval函数的使用方法。
  18. php微信里面换行符,如何在字符串中间加换行符js微信小程序实现人脸识别
  19. AWD平台搭建–Cardinal
  20. 项目三:公寓管理系统_ssm

热门文章

  1. CoLoRMap: Correcting Long Reads by Mapping short reads CoLoRMap:通过映射短读来纠正长读
  2. linux把文件复制到压缩包里,Linux学习笔记(二十)文件压缩 zip压缩、tar打包、打包、解包...
  3. GAN人脸修复--Generative Face Completion
  4. python mysql 分页_利用python对mysql表做全局模糊搜索并分页实例
  5. html form提交前验证,form表单提交前验证实现方法
  6. linux查看全连接队列大小,[TimLinux] TCP全连接队列满
  7. 计算机ppt2003考试试题,计算机模块PPT2003试题及答案.doc
  8. ejs文件与html,将HTMLWebpackPlugin与EJS文件一起使用
  9. 2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码)
  10. 如何在简历中添加自己的CSDN博客链接