Last active
November 3, 2024 14:00
-
-
Save imba-tjd/523b377a0d36d40ae5109826e9eb9a0f to your computer and use it in GitHub Desktop.
Windows httpapi server example.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://learn.microsoft.com/zh-cn/windows/win32/Http | |
// gcc server.c -Os -Wall -lhttpapi -o server | |
#define WIN32_LEAN_AND_MEAN | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <http.h> | |
#include <windows.h> | |
#include <signal.h> | |
static HANDLE hReqQueue; | |
static HTTP_SERVER_SESSION_ID serverSessionId; | |
static HTTP_URL_GROUP_ID urlGroupId; | |
static void cleanup(int) { | |
HttpCloseRequestQueue(hReqQueue); | |
hReqQueue = NULL; // notify receive loop | |
HttpCloseUrlGroup(urlGroupId); | |
HttpCloseServerSession(serverSessionId); | |
HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); | |
puts("Server terminated"); | |
} | |
int main() { | |
ULONG ret; | |
// Initialize HTTP Server API | |
ret = HttpInitialize((HTTPAPI_VERSION)HTTPAPI_VERSION_2, HTTP_INITIALIZE_SERVER, NULL); | |
if (ret != NO_ERROR) { | |
printf("HttpInitialize failed with %lu\n", ret); | |
return ret; | |
} | |
// Create HTTP Server Session | |
ret = HttpCreateServerSession((HTTPAPI_VERSION)HTTPAPI_VERSION_2, &serverSessionId, 0); | |
if (ret != NO_ERROR) { | |
printf("HttpCreateServerSession failed with %lu\n", ret); | |
return ret; | |
} | |
// Create URL Group | |
ret = HttpCreateUrlGroup(serverSessionId, &urlGroupId, 0); | |
if (ret != NO_ERROR) { | |
printf("HttpCreateUrlGroup failed with %lu\n", ret); | |
return ret; | |
} | |
// Create Request Queue | |
ret = HttpCreateRequestQueue((HTTPAPI_VERSION)HTTPAPI_VERSION_2, NULL, NULL, 0, &hReqQueue); | |
if (ret != NO_ERROR) { | |
printf("HttpCreateRequestQueue failed with %lu\n", ret); | |
return ret; | |
} | |
// Bind URL Group to Request Queue | |
HTTP_BINDING_INFO bindingInfo = { | |
.Flags.Present = 1, | |
.RequestQueueHandle = hReqQueue | |
}; | |
ret = HttpSetUrlGroupProperty(urlGroupId, HttpServerBindingProperty, &bindingInfo, sizeof(bindingInfo)); | |
if (ret != NO_ERROR) { | |
printf("HttpSetUrlGroupProperty failed with %lu\n", ret); | |
return ret; | |
} | |
// Set URL | |
ret = HttpAddUrlToUrlGroup(urlGroupId, L"http://localhost:8080/", 0, 0); | |
if (ret != NO_ERROR) { | |
printf("HttpAddUrlToUrlGroup failed with %lu\n", ret); | |
return ret; | |
} | |
signal(SIGINT, cleanup); | |
puts("Server started on http://localhost:8080"); | |
// Main loop to handle requests | |
while (1) { | |
if (!hReqQueue) return 0; // cleaned in SIGINT | |
// Initialize request structure | |
#define requestBufferLength (sizeof(HTTP_REQUEST) + 1024) | |
char requestBuffer[requestBufferLength] = {0}; | |
HTTP_REQUEST *request = (HTTP_REQUEST*) requestBuffer; | |
// Receive a request | |
DWORD bytesRead; | |
ret = HttpReceiveHttpRequest(hReqQueue, HTTP_NULL_ID, 0, request, requestBufferLength, &bytesRead, NULL); | |
if (ret != NO_ERROR) { | |
printf("HttpReceiveHttpRequest failed with %lu\n", ret); | |
continue; | |
} | |
// Log remote addr | |
PSOCKADDR_IN r = (PSOCKADDR_IN)request->Address.pRemoteAddress; | |
#define SIN_ADDR_B(s) (s->sin_addr.S_un.S_un_b) | |
printf("Received from %hhu.%hhu.%hhu.%hhu:%hu\n", | |
SIN_ADDR_B(r).s_b1, SIN_ADDR_B(r).s_b2, SIN_ADDR_B(r).s_b3, SIN_ADDR_B(r).s_b4, r->sin_port); | |
// Initialize the response | |
HTTP_RESPONSE response = { | |
.StatusCode = 200, | |
.pReason = "OK", | |
}; | |
response.ReasonLength = (USHORT)strlen(response.pReason); | |
response.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = "text/plain"; | |
response.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen(response.Headers.KnownHeaders[HttpHeaderContentType].pRawValue); | |
// Response body | |
const char* responseBody = "Hello, World!"; | |
HTTP_DATA_CHUNK dataChunk = { | |
.DataChunkType = HttpDataChunkFromMemory, | |
.FromMemory = { | |
.pBuffer = (PVOID)responseBody, | |
.BufferLength = (ULONG)strlen(responseBody) | |
} | |
}; | |
response.EntityChunkCount = 1; | |
response.pEntityChunks = &dataChunk; | |
// Send the response | |
DWORD bytesSent; | |
ret = HttpSendHttpResponse(hReqQueue, request->RequestId, HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA, &response, NULL, &bytesSent, NULL, 0, NULL, NULL); | |
if (ret != NO_ERROR) { | |
printf("HttpSendHttpResponse failed with %lu\n", ret); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Unfinished pyx binding with some notes:
HTTP_REQUEST_V2“继承”了HTTP_REQUEST_V1。Vista后HTTP_REQUEST就是V2